From 9b773ee7999ae3d69c19ca6fb9b40be4e08274e2 Mon Sep 17 00:00:00 2001 From: Ryan Winter Date: Thu, 9 Nov 2023 09:43:07 -0800 Subject: [PATCH 1/4] clean up go sample Signed-off-by: Ryan Winter --- samples/dapr-quickstart-go/go.mod | 2 +- samples/dapr-quickstart-go/go.sum | 6 ++ samples/dapr-quickstart-go/main.go | 111 ++++++++++------------------- 3 files changed, 43 insertions(+), 76 deletions(-) diff --git a/samples/dapr-quickstart-go/go.mod b/samples/dapr-quickstart-go/go.mod index bdbe864..c10b47e 100644 --- a/samples/dapr-quickstart-go/go.mod +++ b/samples/dapr-quickstart-go/go.mod @@ -1,6 +1,6 @@ module dapr-quickstart-go -go 1.20 +go 1.21 require github.com/dapr/go-sdk v1.9.1 diff --git a/samples/dapr-quickstart-go/go.sum b/samples/dapr-quickstart-go/go.sum index c73d38d..47f49f3 100644 --- a/samples/dapr-quickstart-go/go.sum +++ b/samples/dapr-quickstart-go/go.sum @@ -4,14 +4,17 @@ github.com/dapr/dapr v1.12.0-rc.4/go.mod h1:JZGZh8T0rz75DZBX3zGESi1p9IWWM0ZAGAza github.com/dapr/go-sdk v1.9.1 h1:f5gV8HtGz6iBJSsh6eI+/Ews4sGC3W9gX0/oD9ANVqM= github.com/dapr/go-sdk v1.9.1/go.mod h1:bK9bNEsC6hY3RMKh69r0nBjLqb6njeWTEGVMOgP9g20= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -20,9 +23,11 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= @@ -40,5 +45,6 @@ google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/samples/dapr-quickstart-go/main.go b/samples/dapr-quickstart-go/main.go index 7097123..a92b115 100644 --- a/samples/dapr-quickstart-go/main.go +++ b/samples/dapr-quickstart-go/main.go @@ -1,26 +1,14 @@ -/* -Copyright 2021 The Dapr Authors -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. package main import ( "context" "encoding/json" - "errors" "log" "net/http" "strconv" - "time" dapr "github.com/dapr/go-sdk/client" "github.com/dapr/go-sdk/service/common" @@ -32,63 +20,50 @@ type OrderDetails struct { Name string `json:"item"` } -var ( - c dapr.Client - err error - ctx context.Context +const ( + stateStoreComponentName = "aio-mq-statestore" + pubSubComponentName = "aio-mq-pubsub" + daprServerPort = ":6001" ) -var ordersSub = &common.Subscription{ - PubsubName: "aio-mq-pubsub", +var ordersSubscription = &common.Subscription{ + PubsubName: pubSubComponentName, Topic: "orders", - Route: "/orders", + Route: "/some-orders", } -var oddOrdersSub = &common.Subscription{ - PubsubName: "aio-mq-pubsub", +var oddOrdersSubscription = &common.Subscription{ + PubsubName: pubSubComponentName, Topic: "odd-numbered-orders", - Route: "/odd-orders", -} - -func init() { - // wait for sidecar - time.Sleep(13 * time.Second) + Route: "/odd-numbered-orders", } func main() { + // create a Dapr service for subscribing + server := daprd.NewService(daprServerPort) - c, err := dapr.NewClient() + // create a Dapr client for publishing + client, err := dapr.NewClient() if err != nil { panic(err) } - // create a Dapr service - s := daprd.NewService(":6001") - - if err := s.AddTopicEventHandler(ordersSub, eventHandler(c)); err != nil { - + if err := server.AddTopicEventHandler(ordersSubscription, ordersEventHandler(client)); err != nil { log.Fatalf("error adding topic subscription: %v", err) } - if err := s.AddTopicEventHandler(oddOrdersSub, oddOrdersHandler(c)); err != nil { - + if err := server.AddTopicEventHandler(oddOrdersSubscription, oddOrdersEventHandler(client)); err != nil { log.Fatalf("error adding topic subscription: %v", err) } - // add a service to service invocation handler - if err := s.AddServiceInvocationHandler("/get-order", orderGetter(c)); err != nil { - log.Fatalf("error adding invocation handler: %v", err) - } - - if err := s.Start(); err != nil && err != http.ErrServerClosed { + if err := server.Start(); err != nil && err != http.ErrServerClosed { log.Fatalf("error listening: %v", err) } } -func eventHandler(c dapr.Client) common.TopicEventHandler { - +func ordersEventHandler(client dapr.Client) common.TopicEventHandler { return func(ctx context.Context, e *common.TopicEvent) (retry bool, err error) { - log.Printf("event - PubsubName:%s, Topic:%s, ID:%s, Data: %s", e.PubsubName, e.Topic, e.ID, e.Data) + log.Printf("orders event - PubsubName: %s, Topic: %s, ID: %s, Data: %s", e.PubsubName, e.Topic, e.ID, e.Data) var order OrderDetails s, _ := strconv.Unquote(string(e.RawData)) @@ -103,7 +78,7 @@ func eventHandler(c dapr.Client) common.TopicEventHandler { if order.Number%2 != 0 { // PubsubName seems to be in e.Topic when published by a pure MQTT client - if err := c.PublishEvent(ctx, e.Topic, "odd-numbered-orders", e.Data); err != nil { + if err := client.PublishEvent(ctx, e.Topic, "odd-numbered-orders", e.Data); err != nil { panic(err) } log.Printf("Published to odd-numbered-orders: %v", e) @@ -113,10 +88,10 @@ func eventHandler(c dapr.Client) common.TopicEventHandler { } } -func oddOrdersHandler(c dapr.Client) common.TopicEventHandler { - +func oddOrdersEventHandler(client dapr.Client) common.TopicEventHandler { return func(ctx context.Context, e *common.TopicEvent) (retry bool, err error) { - log.Printf("event - PubsubName:%s, Topic:%s, ID:%s, Data: %s", e.PubsubName, e.Topic, e.ID, e.Data) + log.Printf("addOrders event - PubsubName: %s, Topic: %s, ID: %s, Data: %s", e.PubsubName, e.Topic, e.ID, e.Data) + var order OrderDetails err = json.Unmarshal([]byte(e.RawData), &order) if err != nil { @@ -125,38 +100,24 @@ func oddOrdersHandler(c dapr.Client) common.TopicEventHandler { } log.Printf("Odd order number is %d with name %s", order.Number, order.Name) - STATE_STORE_NAME := "aio-mq-statestore" - if err := c.SaveState(ctx, STATE_STORE_NAME, strconv.FormatUint(uint64(order.Number), 10), []byte(order.Name), nil); err != nil { + // save to the state store + if err := client.SaveState(ctx, stateStoreComponentName, strconv.FormatUint(uint64(order.Number), 10), []byte(order.Name), nil); err != nil { log.Printf("Error saving state: %v", err) return true, err } log.Printf("Saved order #%d", order.Number) - return false, nil - } -} - -func orderGetter(c dapr.Client) common.ServiceInvocationHandler { - return func(ctx context.Context, in *common.InvocationEvent) (out *common.Content, err error) { - if in == nil { - err = errors.New("invocation parameter required") - return - } - log.Printf( - "echo - ContentType:%s, Verb:%s, QueryString:%s, %s", - in.ContentType, in.Verb, in.QueryString, in.Data, - ) - - STATE_STORE_NAME := "aio-mq-statestore" - result, _ := c.GetState(ctx, STATE_STORE_NAME, string(in.Data), nil) - - out = &common.Content{ - Data: result.Value, - ContentType: in.ContentType, - DataTypeURL: in.DataTypeURL, + // get from the state store + state, err := client.GetState(ctx, stateStoreComponentName, strconv.FormatUint(uint64(order.Number), 10), nil); + if err != nil { + log.Printf("Error getting state: %v", err) + return true, err } - return + + log.Printf("Got order #%d, state %s", order.Number, state.Value) + + return false, nil } } From b62dc1ec16a1e1367dc4bf55897d7e7196405ead Mon Sep 17 00:00:00 2001 From: Venkat Yalla Date: Thu, 9 Nov 2023 10:00:09 -0800 Subject: [PATCH 2/4] Add fabric tutorial for real-time dashboards with event streaming (#18) Add fabric tutorial for real-time dashboards with event streaming --- .../deployMqConnector.bicep | 190 ++++++++++++++++++ .../simulate-data.yaml | 94 +++++++++ 2 files changed, 284 insertions(+) create mode 100644 tutorials/mq-realtime-fabric-dashboard/deployMqConnector.bicep create mode 100644 tutorials/mq-realtime-fabric-dashboard/simulate-data.yaml diff --git a/tutorials/mq-realtime-fabric-dashboard/deployMqConnector.bicep b/tutorials/mq-realtime-fabric-dashboard/deployMqConnector.bicep new file mode 100644 index 0000000..7f9279b --- /dev/null +++ b/tutorials/mq-realtime-fabric-dashboard/deployMqConnector.bicep @@ -0,0 +1,190 @@ + +metadata description = 'This template deploys MQ Kafka Connector, Event Hubs, and configures role assignments' + +/*****************************************************************************/ +/* Deployment Parameters */ +/*****************************************************************************/ + + +param location string = any(resourceGroup().location) + +param customLocationName string = '${any(resourceGroup().name)}-cl' +param mqInstanceName string = 'mq-instance' +param clusterName string = 'iot-operations-cluster' +param mqExtensionName string = 'mq' + +/*****************************************************************************/ +/* Constants */ +/*****************************************************************************/ + +var repo = 'mcr.microsoft.com/azureiotoperations' +var imageTag = '0.1.0-preview' + + + +/*****************************************************************************/ +/* Existing resources. */ +/*****************************************************************************/ + +resource customLocation 'Microsoft.ExtendedLocation/customLocations@2021-08-31-preview' existing = { + name: customLocationName +} + +resource mq 'Microsoft.IoTOperationsMQ/mq@2023-10-04-preview' existing = { + name: mqInstanceName +} + +resource cluster 'Microsoft.Kubernetes/connectedClusters@2021-03-01' existing = { + name: clusterName +} + +resource mqExtension 'Microsoft.KubernetesConfiguration/extensions@2022-03-01' existing = { + scope: cluster + name: mqExtensionName +} + + +/*****************************************************************************/ +/* Cloud resources */ +/*****************************************************************************/ + +var eventHubSku = 'Standard' + + +resource eventHubNamespace 'Microsoft.EventHub/namespaces@2021-11-01' = { + name: 'ehns-${uniqueString(resourceGroup().id)}' + location: location + sku: { + name: eventHubSku + tier: eventHubSku + capacity: 1 + } + properties: { + isAutoInflateEnabled: false + maximumThroughputUnits: 0 + } +} + +resource eventHub 'Microsoft.EventHub/namespaces/eventhubs@2017-04-01' = { + parent: eventHubNamespace + name: 'eh-eventstream' + properties: { + messageRetentionInDays: 7 + partitionCount: 1 + } +} + +resource eventHubCg 'Microsoft.EventHub/namespaces/eventhubs/consumergroups@2017-04-01' = { + parent: eventHub + name: 'eventHubConsumerGroup' + properties: {} +} + + +/*****************************************************************************/ +/* MQ resources. */ +/*****************************************************************************/ + +var mqttTopic = 'sensor/data' + +resource kafkaConnector 'Microsoft.IoTOperationsMQ/mq/kafkaConnector@2023-10-04-preview' = { + parent: mq + name: 'kafka-conntr' + location: location + extendedLocation: { + name: customLocation.id + type: 'CustomLocation' + } + properties: { + image: { + pullPolicy: 'Always' + repository: '${repo}/kafka' + tag: imageTag + } + instances: 1 + kafkaConnection: { + endpoint: '${eventHubNamespace.name}.servicebus.windows.net:9093' + tls: { + tlsEnabled: true + } + authentication: { + enabled: true + authType: { + systemAssignedManagedIdentity: { + audience: 'https://${eventHubNamespace.name}.servicebus.windows.net' + } + } + } + } + localBrokerConnection: { + endpoint: 'aio-mq-dmqtt-frontend:8883' + authentication: { + kubernetes: {} + } + tls: { + tlsEnabled: true + trustedCaCertificateConfigMap: 'aio-ca-trust-bundle-test-only' + } + } + } + dependsOn: [ + eventHubNamespace + ] +} + +resource kcTopicmap 'Microsoft.IoTOperationsMQ/mq/kafkaConnector/topicMap@2023-10-04-preview' = { + parent: kafkaConnector + name: 'kc-topicmap' + location: location + extendedLocation: { + name: customLocation.id + type: 'CustomLocation' + } + properties: { + kafkaConnectorRef: kafkaConnector.name + compression: 'none' + batching: { + enabled: false + } + routes: [ + { + mqttToKafka: { + kafkaTopic: eventHub.name + mqttTopic: mqttTopic + name: 'dataTopic' + kafkaAcks: 'one' + } + } + ] + } +} + + +/*****************************************************************************/ +/* Role assignments */ +/*****************************************************************************/ + +// Role assignment for Event Hub Data Receiver role +resource roleAssignmentDataReceiver 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(eventHubNamespace.id, mqExtension.id, '7f951dda-4ed3-4680-a7ca-43fe172d538d') + scope: eventHubNamespace + properties: { + // ID for Event Hub Data Receiver role is a638d3c7-ab3a-418d-83e6-5f17a39d4fde + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', 'a638d3c7-ab3a-418d-83e6-5f17a39d4fde') + principalId: mqExtension.identity.principalId + principalType: 'ServicePrincipal' + } +} + +// Role assignment for Event Hub Data Sender role +resource roleAssignmentDataSender 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(eventHubNamespace.id, mqExtension.id, '69b88ce2-a752-421f-bd8b-e230189e1d63') + scope: eventHubNamespace + properties: { + // ID for Event Hub Data Sender role is 2b629674-e913-4c01-ae53-ef4638d8f975 + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', '2b629674-e913-4c01-ae53-ef4638d8f975') + principalId: mqExtension.identity.principalId + principalType: 'ServicePrincipal' + } +} + diff --git a/tutorials/mq-realtime-fabric-dashboard/simulate-data.yaml b/tutorials/mq-realtime-fabric-dashboard/simulate-data.yaml new file mode 100644 index 0000000..e9972ca --- /dev/null +++ b/tutorials/mq-realtime-fabric-dashboard/simulate-data.yaml @@ -0,0 +1,94 @@ + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: mqtt-publisher + namespace: azure-iot-operations +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mqtt-publisher-deployment + namespace: azure-iot-operations +spec: + replicas: 1 + selector: + matchLabels: + app: mqtt-publisher + template: + metadata: + labels: + app: mqtt-publisher + spec: + serviceAccountName: mqtt-publisher + containers: + - name: mqtt-publisher + image: debian:stable-slim + env: + - name: MQTT_TOPIC + value: "sensor/data" + - name: MQTTUI_BROKER + value: 'mqtts://aio-mq-dmqtt-frontend:8883' + - name: MQTTUI_USERNAME + value: '$sat' + - name: SLEEP_DURATION + value: "0.2" + command: ["/bin/sh"] + args: + - -c + - | + apt-get update && apt-get install -y jq curl bc + curl -LO https://github.com/EdJoPaTo/mqttui/releases/download/v0.19.0/mqttui-v0.19.0-x86_64-unknown-linux-gnu.deb + apt-get install ./mqttui-v0.19.0-x86_64-unknown-linux-gnu.deb + export MQTTUI_PASSWORD=$(cat /var/run/secrets/tokens/mqtt-client-token) + MSG_COUNT=0 + SECONDS=0 + REPORT_INTERVAL=10 + while true; do + # Generate random values for temperature, pressure and vibration + PRES=$(awk -v min=290 -v max=300 'BEGIN{srand(); print min+rand()*(max-min)}') + TEMP=$(awk -v min=550 -v max=600 'BEGIN{srand(); print min+rand()*(max-min)}') + VIB=$(awk -v min=0.001 -v max=0.005 'BEGIN{srand(); print min+rand()*(max-min)}') + + DATA=$(jq -n \ + --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ")" \ + --arg id "Sensor-$(hostname)-$$" \ + --argjson temp "$TEMP" \ + --argjson pres "$PRES" \ + --argjson vib "$VIB" \ + '{ + timestamp: $ts, + sensor_id: $id, + temperature: $temp, + pressure: $pres, + vibration: $vib + }') + + mqttui publish -i "iiot-scenario-walkthru" --insecure $MQTT_TOPIC "$DATA" + + MSG_COUNT=$((MSG_COUNT+1)) + + # Use awk to add a floating point number to SECONDS + SECONDS=$(awk -v sec=$SECONDS -v dur=$SLEEP_DURATION 'BEGIN {print sec + dur}') + + if [ $(echo "$SECONDS / $REPORT_INTERVAL" | bc) -gt 0 ]; then + echo "Messages published in the last $REPORT_INTERVAL seconds: $MSG_COUNT" + MSG_COUNT=0 + SECONDS=0 + fi + + sleep $SLEEP_DURATION + + done + volumeMounts: + - name: mqtt-client-token + mountPath: "/var/run/secrets/tokens" + readOnly: true + volumes: + - name: mqtt-client-token + projected: + sources: + - serviceAccountToken: + path: mqtt-client-token + expirationSeconds: 86400 + audience: "aio-mq" \ No newline at end of file From ae26cae48d91d4f47ac7d04f1e90fa7d15878b5f Mon Sep 17 00:00:00 2001 From: Ethan Date: Thu, 9 Nov 2023 11:45:16 -0800 Subject: [PATCH 3/4] Restore the state of the main branch and add back in the three commits which followed the break --- .devcontainer/Dockerfile | 8 +- .devcontainer/devcontainer.json | 76 +- .devcontainer/postCreateCommand.sh | 6 +- .github/workflows/docker_build.yml | 1 - .gitignore | 4 - docker/example/Dockerfile | 9 - lib/example/example.go | 11 - lib/example/example_test.go | 8 - go.mod => lib/mage/go.mod | 2 +- go.sum => lib/mage/go.sum | 0 mageerrors.go => lib/mage/mageerrors.go | 0 magefile.go => lib/mage/magefile.go | 0 samples/callout/.gitignore | 24 + samples/callout/.vscode/launch.json | 19 + samples/callout/Dockerfile | 23 + samples/callout/README.md | 76 + samples/callout/cmd/config.go | 23 + samples/callout/cmd/main.go | 148 + samples/callout/go.mod | 37 + samples/callout/go.sum | 502 ++ samples/callout/pkg/models/quality.go | 25 + samples/callout/pkg/serving/admin.go | 39 + samples/callout/pkg/serving/echoRequest.go | 38 + samples/callout/pkg/serving/qFactor.go | 60 + samples/callout/setup/service.yaml | 42 + samples/dapr-quickstart-go/go.mod | 2 +- samples/dapr-quickstart-go/go.sum | 2 +- samples/dapr-quickstart-go/main.go | 2 +- .../aio-health-1698853504944.json | 1474 +++++ ...io-health-infra-cluster-1698853541941.json | 1353 +++++ .../aio-health-infra-pod-1698853566878.json | 2099 ++++++++ ...o-health-infra-workload-1698853576137.json | 2458 +++++++++ ...aio-health-service-akri-1698853585126.json | 3845 +++++++++++++ .../aio-health-service-dp-1698853592723.json | 4792 +++++++++++++++++ .../aio-health-service-mq-1698853600657.json | 3861 +++++++++++++ ...io-health-service-opcua-1698853611489.json | 4434 +++++++++++++++ ...aio-health-service-orch-1698853622327.json | 3333 ++++++++++++ ...service-dp-messagestore-1698853668951.json | 1469 +++++ ...aio-service-dp-overview-1698853677638.json | 2421 +++++++++ ...aio-service-dp-pipeline-1698853686073.json | 2615 +++++++++ .../aio-service-dp-runner-1698853694635.json | 1642 ++++++ .../aio-service-dp-stage-1698853700645.json | 1073 ++++ .../aio-service-lnm-1698853706938.json | 1864 +++++++ ...ludes selftest traffic)-1698853748637.json | 576 ++ .../aio-service-mq-bridges-1698853739458.json | 575 ++ .../aio-service-mq-main-1698853755082.json | 1586 ++++++ .../aio-service-mq-ping-1698853769308.json | 899 ++++ .../aio-service-mq-publish-1698853774663.json | 1044 ++++ ...-service-mq-state-store-1698853779699.json | 411 ++ ...io-service-mq-subscribe-1698853784238.json | 1018 ++++ .../aio-service-opcua-1698853789067.json | 1893 +++++++ .../health-service-akri-1698853793929.json | 3910 ++++++++++++++ .../undefined-1698853744219.json | 5 + samples/dashboard/insightsTemplate.pbit | Bin 0 -> 102682 bytes samples/example/config.yaml | 2 - samples/krill/.gitignore | 16 + samples/krill/.golangci.yml | 36 + samples/krill/Dockerfile | 17 + samples/krill/README.md | 184 + samples/krill/cmd/krill/main.go | 201 + samples/krill/components/broker/broker.go | 59 + .../krill/components/broker/broker_test.go | 30 + samples/krill/components/broker/service.go | 48 + .../krill/components/broker/service_test.go | 74 + samples/krill/components/client/client.go | 356 ++ .../krill/components/client/client_test.go | 533 ++ samples/krill/components/client/clientv5.go | 261 + samples/krill/components/client/errors.go | 32 + samples/krill/components/client/service.go | 146 + .../krill/components/client/service_test.go | 397 ++ samples/krill/components/edge/edge_test.go | 202 + samples/krill/components/edge/errors.go | 61 + samples/krill/components/edge/service.go | 97 + samples/krill/components/formatter/errors.go | 21 + .../krill/components/formatter/formatter.go | 198 + .../components/formatter/formatter_test.go | 170 + samples/krill/components/formatter/service.go | 63 + .../components/formatter/service_test.go | 111 + samples/krill/components/limiter/errors.go | 25 + samples/krill/components/limiter/limiter.go | 121 + .../krill/components/limiter/limiter_test.go | 80 + samples/krill/components/limiter/service.go | 53 + .../krill/components/limiter/service_test.go | 67 + samples/krill/components/node/errors.go | 33 + samples/krill/components/node/node_test.go | 101 + samples/krill/components/node/service.go | 74 + samples/krill/components/observer/observer.go | 56 + .../components/observer/observer_test.go | 78 + samples/krill/components/observer/service.go | 52 + .../krill/components/observer/service_test.go | 116 + samples/krill/components/outlet/outlet.go | 70 + .../krill/components/outlet/outlet_test.go | 85 + samples/krill/components/outlet/service.go | 62 + .../krill/components/outlet/service_test.go | 92 + samples/krill/components/provider/errors.go | 21 + samples/krill/components/provider/provider.go | 47 + .../components/provider/provider_test.go | 31 + samples/krill/components/provider/service.go | 110 + .../krill/components/provider/service_test.go | 192 + .../krill/components/publisher/publisher.go | 148 + .../components/publisher/publisher_test.go | 156 + samples/krill/components/publisher/service.go | 140 + .../components/publisher/service_test.go | 228 + samples/krill/components/registry/registry.go | 107 + .../components/registry/registry_test.go | 58 + samples/krill/components/registry/service.go | 28 + .../krill/components/registry/service_test.go | 27 + samples/krill/components/renderer/renderer.go | 40 + .../components/renderer/renderer_test.go | 47 + samples/krill/components/renderer/service.go | 47 + .../krill/components/renderer/service_test.go | 79 + samples/krill/components/site/service.go | 46 + samples/krill/components/site/service_test.go | 74 + samples/krill/components/site/site.go | 43 + samples/krill/components/site/site_test.go | 17 + .../krill/components/subscriber/service.go | 116 + .../components/subscriber/service_test.go | 267 + .../krill/components/subscriber/subscriber.go | 115 + .../components/subscriber/subscriber_test.go | 152 + samples/krill/components/topic/service.go | 46 + .../krill/components/topic/service_test.go | 74 + samples/krill/components/topic/topic.go | 38 + samples/krill/components/topic/topic_test.go | 25 + samples/krill/components/tracer/service.go | 54 + .../krill/components/tracer/service_test.go | 76 + samples/krill/components/tracer/tracer.go | 71 + .../krill/components/tracer/tracer_test.go | 46 + samples/krill/configs/simple/config.yml | 22 + samples/krill/go.mod | 51 + samples/krill/go.sum | 207 + samples/krill/lib/binary/binary.go | 64 + samples/krill/lib/binary/binary_test.go | 77 + samples/krill/lib/component/component.go | 19 + samples/krill/lib/component/component_test.go | 73 + samples/krill/lib/component/errors.go | 7 + samples/krill/lib/component/mock.go | 46 + samples/krill/lib/component/store.go | 77 + samples/krill/lib/component/store_test.go | 71 + samples/krill/lib/composition/composition.go | 179 + .../krill/lib/composition/composition_test.go | 128 + samples/krill/lib/composition/mock.go | 27 + samples/krill/lib/counter/counter.go | 145 + samples/krill/lib/counter/counter_test.go | 104 + samples/krill/lib/dialer/dialer.go | 147 + samples/krill/lib/dialer/dialer_test.go | 121 + samples/krill/lib/env/env.go | 98 + samples/krill/lib/env/env_test.go | 166 + samples/krill/lib/env/errors.go | 25 + samples/krill/lib/environment/environment.go | 46 + .../krill/lib/environment/environment_test.go | 30 + samples/krill/lib/errors/errors.go | 49 + samples/krill/lib/errors/errors_test.go | 143 + samples/krill/lib/errors/fiber.go | 90 + samples/krill/lib/exporter/exporter.go | 153 + samples/krill/lib/exporter/exporter_test.go | 236 + samples/krill/lib/exporter/mock.go | 49 + samples/krill/lib/exporter/provider.go | 50 + samples/krill/lib/exporter/stat.go | 29 + samples/krill/lib/expression/expression.go | 465 ++ .../krill/lib/expression/expression_test.go | 200 + samples/krill/lib/flatten/flatten.go | 103 + samples/krill/lib/flatten/flatten_test.go | 88 + samples/krill/lib/gauge/gauge.go | 129 + samples/krill/lib/gauge/gauge_test.go | 104 + samples/krill/lib/histogram/histogram.go | 170 + samples/krill/lib/histogram/histogram_test.go | 110 + samples/krill/lib/krill/configuration.go | 138 + samples/krill/lib/krill/krill.go | 470 ++ samples/krill/lib/krill/krill_test.go | 448 ++ samples/krill/lib/logger/logger.go | 210 + samples/krill/lib/logger/logger_test.go | 44 + samples/krill/lib/proto/gen.sh | 3 + samples/krill/lib/proto/message.pb.go | 246 + samples/krill/lib/proto/message.proto | 13 + samples/krill/lib/proto/proto.go | 100 + samples/krill/lib/proto/proto_test.go | 36 + samples/krill/lib/templater/templater.go | 85 + samples/krill/lib/templater/templater_test.go | 105 + scripts/arcConnect.sh | 129 + tools/example/cmd/main.go | 10 - tools/example/pkg/example/example.go | 11 - tools/example/pkg/example/example_test.go | 8 - 182 files changed, 65127 insertions(+), 110 deletions(-) delete mode 100644 docker/example/Dockerfile delete mode 100644 lib/example/example.go delete mode 100644 lib/example/example_test.go rename go.mod => lib/mage/go.mod (87%) rename go.sum => lib/mage/go.sum (100%) rename mageerrors.go => lib/mage/mageerrors.go (100%) rename magefile.go => lib/mage/magefile.go (100%) create mode 100644 samples/callout/.gitignore create mode 100644 samples/callout/.vscode/launch.json create mode 100644 samples/callout/Dockerfile create mode 100644 samples/callout/README.md create mode 100644 samples/callout/cmd/config.go create mode 100644 samples/callout/cmd/main.go create mode 100644 samples/callout/go.mod create mode 100644 samples/callout/go.sum create mode 100644 samples/callout/pkg/models/quality.go create mode 100644 samples/callout/pkg/serving/admin.go create mode 100644 samples/callout/pkg/serving/echoRequest.go create mode 100644 samples/callout/pkg/serving/qFactor.go create mode 100644 samples/callout/setup/service.yaml create mode 100644 samples/dashboard/grafana-dashboards/aio-health-1698853504944.json create mode 100644 samples/dashboard/grafana-dashboards/aio-health-infra-cluster-1698853541941.json create mode 100644 samples/dashboard/grafana-dashboards/aio-health-infra-pod-1698853566878.json create mode 100644 samples/dashboard/grafana-dashboards/aio-health-infra-workload-1698853576137.json create mode 100644 samples/dashboard/grafana-dashboards/aio-health-service-akri-1698853585126.json create mode 100644 samples/dashboard/grafana-dashboards/aio-health-service-dp-1698853592723.json create mode 100644 samples/dashboard/grafana-dashboards/aio-health-service-mq-1698853600657.json create mode 100644 samples/dashboard/grafana-dashboards/aio-health-service-opcua-1698853611489.json create mode 100644 samples/dashboard/grafana-dashboards/aio-health-service-orch-1698853622327.json create mode 100644 samples/dashboard/grafana-dashboards/aio-service-dp-messagestore-1698853668951.json create mode 100644 samples/dashboard/grafana-dashboards/aio-service-dp-overview-1698853677638.json create mode 100644 samples/dashboard/grafana-dashboards/aio-service-dp-pipeline-1698853686073.json create mode 100644 samples/dashboard/grafana-dashboards/aio-service-dp-runner-1698853694635.json create mode 100644 samples/dashboard/grafana-dashboards/aio-service-dp-stage-1698853700645.json create mode 100644 samples/dashboard/grafana-dashboards/aio-service-lnm-1698853706938.json create mode 100644 samples/dashboard/grafana-dashboards/aio-service-mq-Current traffic (includes selftest traffic)-1698853748637.json create mode 100644 samples/dashboard/grafana-dashboards/aio-service-mq-bridges-1698853739458.json create mode 100644 samples/dashboard/grafana-dashboards/aio-service-mq-main-1698853755082.json create mode 100644 samples/dashboard/grafana-dashboards/aio-service-mq-ping-1698853769308.json create mode 100644 samples/dashboard/grafana-dashboards/aio-service-mq-publish-1698853774663.json create mode 100644 samples/dashboard/grafana-dashboards/aio-service-mq-state-store-1698853779699.json create mode 100644 samples/dashboard/grafana-dashboards/aio-service-mq-subscribe-1698853784238.json create mode 100644 samples/dashboard/grafana-dashboards/aio-service-opcua-1698853789067.json create mode 100644 samples/dashboard/grafana-dashboards/health-service-akri-1698853793929.json create mode 100644 samples/dashboard/grafana-dashboards/undefined-1698853744219.json create mode 100644 samples/dashboard/insightsTemplate.pbit delete mode 100644 samples/example/config.yaml create mode 100644 samples/krill/.gitignore create mode 100644 samples/krill/.golangci.yml create mode 100644 samples/krill/Dockerfile create mode 100644 samples/krill/README.md create mode 100644 samples/krill/cmd/krill/main.go create mode 100644 samples/krill/components/broker/broker.go create mode 100644 samples/krill/components/broker/broker_test.go create mode 100644 samples/krill/components/broker/service.go create mode 100644 samples/krill/components/broker/service_test.go create mode 100644 samples/krill/components/client/client.go create mode 100644 samples/krill/components/client/client_test.go create mode 100644 samples/krill/components/client/clientv5.go create mode 100644 samples/krill/components/client/errors.go create mode 100644 samples/krill/components/client/service.go create mode 100644 samples/krill/components/client/service_test.go create mode 100644 samples/krill/components/edge/edge_test.go create mode 100644 samples/krill/components/edge/errors.go create mode 100644 samples/krill/components/edge/service.go create mode 100644 samples/krill/components/formatter/errors.go create mode 100644 samples/krill/components/formatter/formatter.go create mode 100644 samples/krill/components/formatter/formatter_test.go create mode 100644 samples/krill/components/formatter/service.go create mode 100644 samples/krill/components/formatter/service_test.go create mode 100644 samples/krill/components/limiter/errors.go create mode 100755 samples/krill/components/limiter/limiter.go create mode 100755 samples/krill/components/limiter/limiter_test.go create mode 100644 samples/krill/components/limiter/service.go create mode 100644 samples/krill/components/limiter/service_test.go create mode 100644 samples/krill/components/node/errors.go create mode 100644 samples/krill/components/node/node_test.go create mode 100644 samples/krill/components/node/service.go create mode 100644 samples/krill/components/observer/observer.go create mode 100644 samples/krill/components/observer/observer_test.go create mode 100644 samples/krill/components/observer/service.go create mode 100644 samples/krill/components/observer/service_test.go create mode 100644 samples/krill/components/outlet/outlet.go create mode 100644 samples/krill/components/outlet/outlet_test.go create mode 100644 samples/krill/components/outlet/service.go create mode 100644 samples/krill/components/outlet/service_test.go create mode 100644 samples/krill/components/provider/errors.go create mode 100644 samples/krill/components/provider/provider.go create mode 100644 samples/krill/components/provider/provider_test.go create mode 100644 samples/krill/components/provider/service.go create mode 100644 samples/krill/components/provider/service_test.go create mode 100644 samples/krill/components/publisher/publisher.go create mode 100644 samples/krill/components/publisher/publisher_test.go create mode 100644 samples/krill/components/publisher/service.go create mode 100644 samples/krill/components/publisher/service_test.go create mode 100644 samples/krill/components/registry/registry.go create mode 100644 samples/krill/components/registry/registry_test.go create mode 100644 samples/krill/components/registry/service.go create mode 100644 samples/krill/components/registry/service_test.go create mode 100644 samples/krill/components/renderer/renderer.go create mode 100644 samples/krill/components/renderer/renderer_test.go create mode 100644 samples/krill/components/renderer/service.go create mode 100644 samples/krill/components/renderer/service_test.go create mode 100644 samples/krill/components/site/service.go create mode 100644 samples/krill/components/site/service_test.go create mode 100644 samples/krill/components/site/site.go create mode 100644 samples/krill/components/site/site_test.go create mode 100644 samples/krill/components/subscriber/service.go create mode 100644 samples/krill/components/subscriber/service_test.go create mode 100644 samples/krill/components/subscriber/subscriber.go create mode 100644 samples/krill/components/subscriber/subscriber_test.go create mode 100644 samples/krill/components/topic/service.go create mode 100644 samples/krill/components/topic/service_test.go create mode 100644 samples/krill/components/topic/topic.go create mode 100644 samples/krill/components/topic/topic_test.go create mode 100644 samples/krill/components/tracer/service.go create mode 100644 samples/krill/components/tracer/service_test.go create mode 100644 samples/krill/components/tracer/tracer.go create mode 100644 samples/krill/components/tracer/tracer_test.go create mode 100644 samples/krill/configs/simple/config.yml create mode 100644 samples/krill/go.mod create mode 100644 samples/krill/go.sum create mode 100644 samples/krill/lib/binary/binary.go create mode 100644 samples/krill/lib/binary/binary_test.go create mode 100644 samples/krill/lib/component/component.go create mode 100644 samples/krill/lib/component/component_test.go create mode 100644 samples/krill/lib/component/errors.go create mode 100644 samples/krill/lib/component/mock.go create mode 100644 samples/krill/lib/component/store.go create mode 100644 samples/krill/lib/component/store_test.go create mode 100644 samples/krill/lib/composition/composition.go create mode 100644 samples/krill/lib/composition/composition_test.go create mode 100644 samples/krill/lib/composition/mock.go create mode 100644 samples/krill/lib/counter/counter.go create mode 100644 samples/krill/lib/counter/counter_test.go create mode 100644 samples/krill/lib/dialer/dialer.go create mode 100644 samples/krill/lib/dialer/dialer_test.go create mode 100644 samples/krill/lib/env/env.go create mode 100644 samples/krill/lib/env/env_test.go create mode 100644 samples/krill/lib/env/errors.go create mode 100644 samples/krill/lib/environment/environment.go create mode 100644 samples/krill/lib/environment/environment_test.go create mode 100644 samples/krill/lib/errors/errors.go create mode 100644 samples/krill/lib/errors/errors_test.go create mode 100644 samples/krill/lib/errors/fiber.go create mode 100644 samples/krill/lib/exporter/exporter.go create mode 100644 samples/krill/lib/exporter/exporter_test.go create mode 100644 samples/krill/lib/exporter/mock.go create mode 100644 samples/krill/lib/exporter/provider.go create mode 100644 samples/krill/lib/exporter/stat.go create mode 100644 samples/krill/lib/expression/expression.go create mode 100644 samples/krill/lib/expression/expression_test.go create mode 100644 samples/krill/lib/flatten/flatten.go create mode 100644 samples/krill/lib/flatten/flatten_test.go create mode 100644 samples/krill/lib/gauge/gauge.go create mode 100644 samples/krill/lib/gauge/gauge_test.go create mode 100644 samples/krill/lib/histogram/histogram.go create mode 100644 samples/krill/lib/histogram/histogram_test.go create mode 100644 samples/krill/lib/krill/configuration.go create mode 100644 samples/krill/lib/krill/krill.go create mode 100644 samples/krill/lib/krill/krill_test.go create mode 100644 samples/krill/lib/logger/logger.go create mode 100644 samples/krill/lib/logger/logger_test.go create mode 100755 samples/krill/lib/proto/gen.sh create mode 100644 samples/krill/lib/proto/message.pb.go create mode 100644 samples/krill/lib/proto/message.proto create mode 100644 samples/krill/lib/proto/proto.go create mode 100644 samples/krill/lib/proto/proto_test.go create mode 100755 samples/krill/lib/templater/templater.go create mode 100755 samples/krill/lib/templater/templater_test.go create mode 100644 scripts/arcConnect.sh delete mode 100644 tools/example/cmd/main.go delete mode 100644 tools/example/pkg/example/example.go delete mode 100644 tools/example/pkg/example/example_test.go diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index b14beff..0b73ed5 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -14,4 +14,10 @@ RUN wget -q https://raw.githubusercontent.com/dapr/cli/master/install/install.sh # Install mqttui RUN wget https://github.com/EdJoPaTo/mqttui/releases/download/v0.19.0/mqttui-v0.19.0-x86_64-unknown-linux-gnu.deb && \ sudo apt-get install ./mqttui-v0.19.0-x86_64-unknown-linux-gnu.deb && \ - rm -rf ./mqttui-v0.19.0-x86_64-unknown-linux-gnu.deb \ No newline at end of file + rm -rf ./mqttui-v0.19.0-x86_64-unknown-linux-gnu.deb + +# Install k9s +RUN wget https://github.com/derailed/k9s/releases/download/v0.28.0/k9s_Linux_amd64.tar.gz && \ + tar xf k9s_Linux_amd64.tar.gz --directory=/usr/local/bin k9s && \ + chmod +x /usr/local/bin/k9s && \ + rm -rf k9s_Linux_amd64.tar.gz \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 2db7a58..b1cf5c3 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,47 +1,43 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the // README at: https://github.com/devcontainers/templates/tree/main/src/kubernetes-helm-minikube { - "name": "Kubernetes - k3d", - // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - // "image": "mcr.microsoft.com/devcontainers/universal:2-linux", - "build": { - "dockerfile": "Dockerfile" - }, - "hostRequirements": { - "cpus": 4, - "memory": "8gb", - "storage": "32gb" + "name": "Kubernetes - k3d", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + // "image": "mcr.microsoft.com/devcontainers/universal:2-linux", + "build": { + "dockerfile": "Dockerfile" + }, + "hostRequirements": { + "cpus": 4, + "memory": "8gb", + "storage": "32gb" + }, + "features": { + "ghcr.io/devcontainers/features/azure-cli:1": { + "extensions": "connectedk8s,k8s-extension" }, - "features": { - "ghcr.io/devcontainers/features/azure-cli:1": { - "extensions": "connectedk8s,k8s-extension" - }, - "ghcr.io/rio/features/k3d:1": {}, - "ghcr.io/rio/features/k9s:1": {} + "ghcr.io/rio/features/k3d:1": {} + }, + "secrets": { + "SUBSCRIPTION_ID": { + "description": "Your Azure subscription ID" }, - "secrets": { - "SUBSCRIPTION_ID": { - "description": "Your Azure subscription ID" - }, - "RESOURCE_GROUP": { - "description": "Your Azure resource group" - }, - "REGION": { - "description": "Region to use, must be one of eastus, eastus2, westus, westus2, westus3, westeurope, or northeurope.", - "documentationUrl": "https://review.learn.microsoft.com/en-us/azure/iot-operations/deploy/howto-prepare-cluster" - } + "RESOURCE_GROUP": { + "description": "Your Azure resource group" }, - "containerEnv": { - "CLUSTER_NAME": "${localEnv:CODESPACE_NAME}" + "REGION": { + "description": "Region to use, must be one of eastus, eastus2, westus, westus2, westus3, westeurope, or northeurope.", + "documentationUrl": "https://review.learn.microsoft.com/en-us/azure/iot-operations/deploy/howto-prepare-cluster" + } }, - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], - // Use 'postCreateCommand' to run commands after the container is created. - "postCreateCommand": "bash ./.devcontainer/postCreateCommand.sh" - // Use 'postStartCommand' to run commands after the container is created like starting minikube. - // "postStartCommand": "nohup bash -c 'minikube start &' > minikube.log 2>&1", - // Configure tool-specific properties. - // "customizations": {}, - // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "root" - } \ No newline at end of file + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "bash ./.devcontainer/postCreateCommand.sh" + // Use 'postStartCommand' to run commands after the container is created like starting minikube. + // "postStartCommand": "nohup bash -c 'minikube start &' > minikube.log 2>&1", + // Configure tool-specific properties. + // "customizations": {}, + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} \ No newline at end of file diff --git a/.devcontainer/postCreateCommand.sh b/.devcontainer/postCreateCommand.sh index 6144c45..59e03ad 100644 --- a/.devcontainer/postCreateCommand.sh +++ b/.devcontainer/postCreateCommand.sh @@ -12,13 +12,17 @@ curl https://raw.githubusercontent.com/rcaloras/bash-preexec/master/bash-preexec echo '[[ -f ~/.bash-preexec.sh ]] && source ~/.bash-preexec.sh' >> ~/.bashrc && \ echo 'eval "$(atuin init bash)"' >> ~/.bashrc +# Install az iot ops extension +# TODO: change to use official extension management method once released +az extension add --source $(curl -w "%{url_effective}\n" -I -L -s -S https://aka.ms/aziotopscli-latest -o /dev/null) -y + # This env var is important to allow k3s to support shared mounts, required for CSI driver # Temporary fix until made default https://github.com/k3d-io/k3d/pull/1268#issuecomment-1745466499 export K3D_FIX_MOUNTS=1 # Create k3d cluster with NFS support and forwarded ports # See https://github.com/jlian/k3d-nfs -k3d cluster create $CLUSTER_NAME -i ghcr.io/jlian/k3d-nfs:v1.25.3-k3s1 \ +k3d cluster create -i ghcr.io/jlian/k3d-nfs:v1.25.3-k3s1 \ -p '1883:1883@loadbalancer' \ -p '8883:8883@loadbalancer' \ -p '6001:6001@loadbalancer' \ diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml index 80abf8e..4e175ae 100644 --- a/.github/workflows/docker_build.yml +++ b/.github/workflows/docker_build.yml @@ -10,7 +10,6 @@ jobs: docker_build: name: 'Build docker containers' runs-on: ubuntu-latest - environment: production defaults: run: diff --git a/.gitignore b/.gitignore index 7bb8afa..8a30d25 100644 --- a/.gitignore +++ b/.gitignore @@ -396,7 +396,3 @@ FodyWeavers.xsd # JetBrains Rider *.sln.iml - -bin -cover.tmp.out -coverage.out \ No newline at end of file diff --git a/docker/example/Dockerfile b/docker/example/Dockerfile deleted file mode 100644 index 05e26a0..0000000 --- a/docker/example/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -# syntax=docker/dockerfile:1 - -FROM mcr.microsoft.com/oss/go/microsoft/golang:1.21-cbl-mariner2.0 - -COPY go.mod /tool/go.mod -COPY go.sum /tool/go.sum -COPY lib /tool/lib -COPY tools/example /tool/example - diff --git a/lib/example/example.go b/lib/example/example.go deleted file mode 100644 index 6c31d3e..0000000 --- a/lib/example/example.go +++ /dev/null @@ -1,11 +0,0 @@ -package example - -import "fmt" - -// Example shows that all exported symbols must have a comment like this. -type Example struct {} - -// Print shows that the exported symbol comments applies to functions as well. -func (*Example) Print() { - fmt.Println("Example library") -} \ No newline at end of file diff --git a/lib/example/example_test.go b/lib/example/example_test.go deleted file mode 100644 index 109a6a8..0000000 --- a/lib/example/example_test.go +++ /dev/null @@ -1,8 +0,0 @@ -package example - -import "testing" - -// Every library must have a test file and must meet a minimum test coverage to be merged into the toolbox. -func TestMain(m *testing.M) { - m.Run() -} diff --git a/go.mod b/lib/mage/go.mod similarity index 87% rename from go.mod rename to lib/mage/go.mod index c0523c8..f295d21 100644 --- a/go.mod +++ b/lib/mage/go.mod @@ -1,4 +1,4 @@ -module github.com/Azure-Samples/aio-dev-toolbox/toolbox +module github.com/Azure-Samples/explore-iot-operations/lib/mage go 1.21.3 diff --git a/go.sum b/lib/mage/go.sum similarity index 100% rename from go.sum rename to lib/mage/go.sum diff --git a/mageerrors.go b/lib/mage/mageerrors.go similarity index 100% rename from mageerrors.go rename to lib/mage/mageerrors.go diff --git a/magefile.go b/lib/mage/magefile.go similarity index 100% rename from magefile.go rename to lib/mage/magefile.go diff --git a/samples/callout/.gitignore b/samples/callout/.gitignore new file mode 100644 index 0000000..7826168 --- /dev/null +++ b/samples/callout/.gitignore @@ -0,0 +1,24 @@ +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ +bin/logs + +# Go workspace file +go.work + +bin \ No newline at end of file diff --git a/samples/callout/.vscode/launch.json b/samples/callout/.vscode/launch.json new file mode 100644 index 0000000..0e7f7d5 --- /dev/null +++ b/samples/callout/.vscode/launch.json @@ -0,0 +1,19 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch", + "type": "go", + "request": "launch", + "mode": "debug", + "cwd": "${workspaceRoot}/bin", + "program": "${workspaceRoot}", + "env": {}, + "args": [], + "showLog": true + } + ] +} \ No newline at end of file diff --git a/samples/callout/Dockerfile b/samples/callout/Dockerfile new file mode 100644 index 0000000..04ea75a --- /dev/null +++ b/samples/callout/Dockerfile @@ -0,0 +1,23 @@ +# syntax=docker/dockerfile:1 + +FROM golang:1.21-alpine + +# Set destination for COPY +WORKDIR /app +ADD . /app + +# Download Go modules +RUN go mod download + +# Build +RUN CGO_ENABLED=0 GOOS=linux go build -o /callout + +# Optional: +# To bind to a TCP port, runtime parameters must be supplied to the docker command. +# But we can document in the Dockerfile what ports +# the application is going to listen on by default. +# https://docs.docker.com/engine/reference/builder/#expose +EXPOSE 8080 + +# Run +CMD ["/callout"] \ No newline at end of file diff --git a/samples/callout/README.md b/samples/callout/README.md new file mode 100644 index 0000000..f816e63 --- /dev/null +++ b/samples/callout/README.md @@ -0,0 +1,76 @@ +# callout +This is a HTTP endpoint that can be used to debug or process data in AIO Data Processor using **Call out HTTP**. + +## Usage + +### Deploy container to Kubernetes cluster + +This utility can be deployed as a service in your Kubernetes cluster. You can use the container that is published to ACR(Azure Container Registry) using [setup/service.yaml](setup/service.yaml) . +``` +kubectl apply -f setup/service.yaml +``` + +### Debugging pipeline +Data Processor has a **Call out HTTP** stage where you can call a HTTP endpoint from with in the pipeline. In that callout stage, you can use the api/echo route to print the contents of the message. Where ever you need to see the message, you can add a callout stage. + +|Parameter | Value | Description | +|----------|-------------|--------------| +| Method | GET or POST | any payload sent in the body is printed as pretty JSON | +| URL | http://callout.default.svc.cluster.local/api/echo/myStage | The URL of the callout endpoint hosted in the cluster. To disambiguate the print outputs, you can use a string like *myStage* or *stage2* etc. | + +### Quality factor +You can compute quality factor using a **Call out HTTP** stage hitting this HTTP endpoint. In that callout stage, you can use the api/qfactor route to comput qFactor, Quality and shift. + +|Parameter | Value | Description | +|----------|-------------|--------------| +| Method | POST | | +| URL | http://callout.default.svc.cluster.local/api/qfactor | | + +#### Input Message #### +```JSON +{ + "Payload": { + "age": 14, + "asset_id": "Red_S1", + "asset_name": "Redmond_Slicer_Redmond_Slicer__asset_0", + "country": "USA", + "humidity": 94.49016579867568, + "id": "Red_S1", + "machine_status": 0, + "operating_time": 12527, + "product": "Takis", + "site": "Redmond", + "source_timestamp": "2023-10-18T18:07:45.575Z", + "temperature": 91.06476575011023, + "vibration": 45.53238287505511 + }, + "SequenceNumber": 12515, + "Timestamp": "2023-10-18T11:07:45.566556393-07:00" +} +``` +#### Output Message #### +```JSON +{ + "Payload": { + "age": 14, + "asset_id": "Red_S1", + "asset_name": "Redmond_Slicer_Redmond_Slicer__asset_0", + "country": "USA", + "humidity": 94.49016579867568, + "id": "Red_S1", + "machine_status": 0, + "operating_time": 12527, + "pressure": 0, + "product": "Takis", + "site": "Redmond", + "temperature": 91.06476575011023, + "vibration": 45.53238287505511, + "q_factor": 0.8, + "quality": "Good", + "shift": 3, + "source_timestamp": "2023-10-18T18:07:45.575Z" + }, + "SequenceNumber": 12515, + "Timestamp": "2023-10-18T11:07:45.566556393-07:00" +} +``` diff --git a/samples/callout/cmd/config.go b/samples/callout/cmd/config.go new file mode 100644 index 0000000..435771f --- /dev/null +++ b/samples/callout/cmd/config.go @@ -0,0 +1,23 @@ +package main + +type ( + Config struct { + LogLevel string `json:"logLevel"` // logging level for the application + LogsDir string `json:"logsDir"` // directory into which logs are written + } + + config struct { + Logger Config `json:"logger"` + Port int `json:"port"` + } +) + +func newConfig() *config { + return &config{ + Logger: Config{ + LogLevel: "Debug", + LogsDir: "./logs", + }, + Port: 8888, + } +} diff --git a/samples/callout/cmd/main.go b/samples/callout/cmd/main.go new file mode 100644 index 0000000..0caee84 --- /dev/null +++ b/samples/callout/cmd/main.go @@ -0,0 +1,148 @@ +package main + +import ( + "context" + _ "embed" + "fmt" + "io" + "os" + "os/signal" + "path" + "strings" + + "github.com/reddydMSFT/callout/pkg/serving" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + "github.com/spf13/viper" + "gopkg.in/natefinch/lumberjack.v2" +) + +func main() { + // handle process exit gracefully + sig := make(chan os.Signal, 1) + signal.Notify(sig, os.Interrupt) + ctx := context.Background() + ctx, cancel := context.WithCancel(ctx) + + defer func() { + // Close the os signal channel to prevent any leak. + signal.Stop(sig) + }() + + // load configuration and initialize logger + cfg, err := loadConfig() + if err != nil { + panic(fmt.Errorf("failed to initialize configuration. %w", err)) + } + initLogger(cfg) + + go serving.StartAdmin(cfg.Port) + + // Wait signal / cancellation + <-sig + + cancel() // Wait for device to completely shut down. +} + +// loadConfig loads the configuration file +func loadConfig() (*config, error) { + colorReset := "\033[0m" + //colorRed := "\033[31m" + colorGreen := "\033[32m" + //colorYellow := "\033[33m" + colorBlue := "\033[34m" + //colorPurple := "\033[35m" + //colorCyan := "\033[36m" + //colorWhite := "\033[37m" + fmt.Printf(string(colorGreen)) + fmt.Printf(` + ██████╗ █████╗ ██╗ ██╗ ██████╗ ██╗ ██╗████████╗ +██╔════╝██╔══██╗██║ ██║ ██╔═══██╗██║ ██║╚══██╔══╝ +██║ ███████║██║ ██║ ██║ ██║██║ ██║ ██║ +██║ ██╔══██║██║ ██║ ██║ ██║██║ ██║ ██║ +╚██████╗██║ ██║███████╗███████╗╚██████╔╝╚██████╔╝ ██║ + ╚═════╝╚═╝ ╚═╝╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ +`) + fmt.Printf(string(colorBlue)) + fmt.Printf(" AIO DATA PROCESSOR CALLOUT\n") + fmt.Printf(string(colorReset)) + + viper.SetConfigName("callout") + viper.SetConfigType("json") + viper.AddConfigPath(".") + viper.AddConfigPath("./bin") + + viper.AutomaticEnv() + if err := viper.ReadInConfig(); err != nil { + if _, ok := err.(viper.ConfigFileNotFoundError); ok { + fmt.Print(`Add a configuration file (callout.json) with the file contents below: + +{ + "logger": { + "logLevel": "Debug", + "logsDir": "./logs" + }, + "port": 8888 +} + +\n`) + return nil, err + } + } + + cfg := newConfig() + if err := viper.Unmarshal(cfg); err != nil { + return nil, err + } + + //fmt.Printf("loaded configuration from %s\n", viper.ConfigFileUsed()) + return cfg, nil +} + +// initLogger initializes the logger with output format +func initLogger(cfg *config) { + var writers []io.Writer + writers = append(writers, zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: "15:04:05"}) + + fileLoggingEnabled := false + if len(cfg.Logger.LogsDir) > 0 { + fileLoggingEnabled = true + } + if fileLoggingEnabled { + logsDir := cfg.Logger.LogsDir + if err := os.MkdirAll(logsDir, 0744); err != nil { + fmt.Printf("can't create log directory, so file logging is disabled, error: %s", err.Error()) + } else { + fileWriter := &lumberjack.Logger{ + Filename: path.Join(logsDir, "callout.log"), + MaxBackups: 3, // files + MaxSize: 10, // megabytes + MaxAge: 30, // days + } + + writers = append(writers, fileWriter) + //fmt.Printf("file logging is enabled, logsDir: %s\n", logsDir) + } + } + mw := io.MultiWriter(writers...) + + log.Logger = zerolog.New(mw).With().Timestamp().Logger() + //log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: "15:04:05"}) + + switch strings.ToLower(cfg.Logger.LogLevel) { + case "panic": + zerolog.SetGlobalLevel(zerolog.PanicLevel) + case "fatal": + zerolog.SetGlobalLevel(zerolog.FatalLevel) + case "error": + zerolog.SetGlobalLevel(zerolog.ErrorLevel) + case "warn": + zerolog.SetGlobalLevel(zerolog.WarnLevel) + case "info": + zerolog.SetGlobalLevel(zerolog.InfoLevel) + case "trace": + zerolog.SetGlobalLevel(zerolog.TraceLevel) + default: + zerolog.SetGlobalLevel(zerolog.DebugLevel) + } +} diff --git a/samples/callout/go.mod b/samples/callout/go.mod new file mode 100644 index 0000000..5a6be47 --- /dev/null +++ b/samples/callout/go.mod @@ -0,0 +1,37 @@ +module github.com/reddydMSFT/callout + +go 1.21.1 + +require github.com/rs/zerolog v1.31.0 + +require ( + github.com/felixge/httpsnoop v1.0.1 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/sagikazarmark/locafero v0.3.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.10.0 // indirect + github.com/spf13/cast v1.5.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/text v0.13.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +require ( + github.com/gorilla/handlers v1.5.1 + github.com/gorilla/mux v1.8.0 + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/spf13/viper v1.17.0 + golang.org/x/sys v0.12.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 +) diff --git a/samples/callout/go.sum b/samples/callout/go.sum new file mode 100644 index 0000000..3e4eba4 --- /dev/null +++ b/samples/callout/go.sum @@ -0,0 +1,502 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= +github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= +github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ= +github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY= +github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI= +github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/samples/callout/pkg/models/quality.go b/samples/callout/pkg/models/quality.go new file mode 100644 index 0000000..a5205e4 --- /dev/null +++ b/samples/callout/pkg/models/quality.go @@ -0,0 +1,25 @@ +package models + +type Quality struct { + Payload struct { + Age int `json:"age"` + AssetID string `json:"asset_id"` + AssetName string `json:"asset_name"` + Country string `json:"country"` + Humidity float64 `json:"humidity"` + ID string `json:"id"` + MachineStatus int `json:"machine_status"` + OperatingTime int `json:"operating_time"` + Pressure float64 `json:"pressure"` + Product string `json:"product"` + Site string `json:"site"` + Temperature float64 `json:"temperature"` + Vibration float64 `json:"vibration"` + QFactor float64 `json:"q_factor"` + Quality string `json:"quality"` + Shift int `json:"shift"` + SourceTimestamp string `json:"source_timestamp"` + } `json:"Payload"` + SequenceNumber int `json:"SequenceNumber"` + Timestamp string `json:"Timestamp"` +} diff --git a/samples/callout/pkg/serving/admin.go b/samples/callout/pkg/serving/admin.go new file mode 100644 index 0000000..2c220e2 --- /dev/null +++ b/samples/callout/pkg/serving/admin.go @@ -0,0 +1,39 @@ +package serving + +import ( + "fmt" + "net/http" + + "github.com/gorilla/handlers" + "github.com/gorilla/mux" + "github.com/rs/zerolog/log" +) + +func StartAdmin(port int) { + router := mux.NewRouter() + + // API routes + router.HandleFunc("/api/echo/{stage}", echoRequest).Methods(http.MethodGet) + router.HandleFunc("/api/echo/{stage}", echoRequest).Methods(http.MethodPost) + router.HandleFunc("/api/qfactor", qFactor).Methods(http.MethodPost) + + log.Info().Msgf("serving callout requests at http://localhost:%d/api", port) + log.Info().Msgf("you can configure callout stage with Get/POST to http://callout.default.svc.cluster.local/api/echo") + + // handle CORS + headersOK := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type", "Authorization"}) + methodsOK := handlers.AllowedMethods([]string{"GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS"}) + originsOK := handlers.AllowedOrigins([]string{"*"}) + + _ = http.ListenAndServe(fmt.Sprintf(":%d", port), handlers.CORS(headersOK, methodsOK, originsOK)(router)) +} + +// handleError log the error and return http error +func handleError(err error, w http.ResponseWriter) bool { + if err != nil { + log.Error().Err(err).Msg("error encountered while processing request") + http.Error(w, err.Error(), http.StatusInternalServerError) + return true + } + return false +} diff --git a/samples/callout/pkg/serving/echoRequest.go b/samples/callout/pkg/serving/echoRequest.go new file mode 100644 index 0000000..98515d3 --- /dev/null +++ b/samples/callout/pkg/serving/echoRequest.go @@ -0,0 +1,38 @@ +package serving + +import ( + "bytes" + "encoding/json" + "io" + "net/http" + + "github.com/gorilla/mux" + "github.com/rs/zerolog/log" +) + +// echo the contents of the body back to response and print to STDOUT +func echoRequest(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + paramStr := "" + for key, value := range vars { + paramStr += key + "=" + value + " " + } + + req, err := io.ReadAll(r.Body) + if handleError(err, w) { + return + } + + // print pretty json + var prettyJSON bytes.Buffer + err = json.Indent(&prettyJSON, req, "", " ") + if handleError(err, w) { + return + } + + log.Debug().Msgf("Request: %s\n%s", paramStr, prettyJSON.String()) + + w.Header().Set("Content-Type", "application/json") + _, err = w.Write(req) + handleError(err, w) +} diff --git a/samples/callout/pkg/serving/qFactor.go b/samples/callout/pkg/serving/qFactor.go new file mode 100644 index 0000000..997c80d --- /dev/null +++ b/samples/callout/pkg/serving/qFactor.go @@ -0,0 +1,60 @@ +package serving + +import ( + "encoding/json" + "io" + "net/http" + "time" + + "github.com/reddydMSFT/callout/pkg/models" +) + +// compute qfactor +func qFactor(w http.ResponseWriter, r *http.Request) { + req, err := io.ReadAll(r.Body) + if handleError(err, w) { + return + } + + var quality models.Quality + err = json.Unmarshal(req, &quality) + if handleError(err, w) { + return + } + + // compute qfactor + var compound = quality.Payload.Temperature * quality.Payload.Humidity + if quality.Payload.Age < 1 { + quality.Payload.QFactor = 1.0 + } else if compound > 7200 && compound <= 8000 { + quality.Payload.QFactor = 0.2 + } else if compound > 8000 && compound <= 9740 { + quality.Payload.QFactor = 0.8 + } else if compound > 9740 && compound <= 11000 { + quality.Payload.QFactor = 0.5 + } else { + quality.Payload.QFactor = 0.0 + } + + // set Quality name + if quality.Payload.QFactor >= 0.6 { + quality.Payload.Quality = "Good" + } else if quality.Payload.QFactor >= 0.3 && quality.Payload.QFactor < 0.6 { + quality.Payload.Quality = "Inspect" + } else { + quality.Payload.Quality = "Bad" + } + + // set Shift info + //aformat := time.RFC3339 + format := "2006-01-02T15:04:05.999Z" + ts, err := time.Parse(format, quality.Payload.SourceTimestamp) + if handleError(err, w) { + return + } + quality.Payload.Shift = (ts.Hour() / 8) + 1 + + w.Header().Set("Content-Type", "application/json") + err = json.NewEncoder(w).Encode(quality) + handleError(err, w) +} diff --git a/samples/callout/setup/service.yaml b/samples/callout/setup/service.yaml new file mode 100644 index 0000000..4747c92 --- /dev/null +++ b/samples/callout/setup/service.yaml @@ -0,0 +1,42 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: callout + namespace: default + labels: + app: callout +spec: + replicas: 1 + selector: + matchLabels: + app: callout + template: + metadata: + labels: + app: callout + spec: + containers: + - name: callout + image: azbluefin.azurecr.io/reddy-callout:stable + imagePullPolicy: Always + ports: + - name: http-8080 + containerPort: 8080 + protocol: TCP +--- +kind: Service +apiVersion: v1 +metadata: + name: callout + namespace: default + labels: + app: callout +spec: + ports: + - name: http-8080 + protocol: TCP + port: 80 + targetPort: 8080 + selector: + app: callout + type: ClusterIP diff --git a/samples/dapr-quickstart-go/go.mod b/samples/dapr-quickstart-go/go.mod index f961c23..9d34474 100644 --- a/samples/dapr-quickstart-go/go.mod +++ b/samples/dapr-quickstart-go/go.mod @@ -17,4 +17,4 @@ require ( google.golang.org/grpc v1.57.1 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect -) +) \ No newline at end of file diff --git a/samples/dapr-quickstart-go/go.sum b/samples/dapr-quickstart-go/go.sum index 4a92f27..c3c73a9 100644 --- a/samples/dapr-quickstart-go/go.sum +++ b/samples/dapr-quickstart-go/go.sum @@ -46,4 +46,4 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= \ No newline at end of file diff --git a/samples/dapr-quickstart-go/main.go b/samples/dapr-quickstart-go/main.go index a92b115..213ff95 100644 --- a/samples/dapr-quickstart-go/main.go +++ b/samples/dapr-quickstart-go/main.go @@ -124,4 +124,4 @@ func oddOrdersEventHandler(client dapr.Client) common.TopicEventHandler { func runHandler(ctx context.Context, in *common.BindingEvent) (out []byte, err error) { log.Printf("binding - Data:%s, Meta:%v", in.Data, in.Metadata) return nil, nil -} +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-health-1698853504944.json b/samples/dashboard/grafana-dashboards/aio-health-1698853504944.json new file mode 100644 index 0000000..0a41136 --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-health-1698853504944.json @@ -0,0 +1,1474 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + }, + { + "name": "VAR_AIO_DP_SELF_TEST_PIPELINE", + "type": "constant", + "label": "aio_dp_self_test_pipeline", + "value": ".*self-test-pipeline.*", + "description": "" + }, + { + "name": "VAR_BF_LATENCY_THRESHOLD_MS", + "type": "constant", + "label": "bf_latency_threshold_ms", + "value": "500", + "description": "" + }, + { + "name": "VAR_AIO_OPC_LATENCY_THRESHOLD_MS", + "type": "constant", + "label": "aio_opc_latency_threshold_ms", + "value": "5000", + "description": "" + }, + { + "name": "VAR_NODETHRESHOLDRED", + "type": "constant", + "label": "nodeThresholdRed", + "value": "90", + "description": "" + }, + { + "name": "VAR_NODETHRESHOLDYELLOW", + "type": "constant", + "label": "nodeThresholdYellow", + "value": "80", + "description": "" + }, + { + "name": "VAR_OPC_SLO_SR_GOAL", + "type": "constant", + "label": "opc_slo_sr_goal", + "value": "99.999", + "description": "" + }, + { + "name": "VAR_OPC_SLO_PUBLISH_LATENCY_MS_GOAL", + "type": "constant", + "label": "opc_slo_publish_latency_ms_goal", + "value": "5000", + "description": "" + }, + { + "name": "VAR_OPC_SLO_CONNECT_LATENCY_MS_GOAL", + "type": "constant", + "label": "opc_slo_connect_latency_ms_goal", + "value": "3000", + "description": "" + }, + { + "name": "VAR_ORC_LATENCY_THRESHOLD_MS", + "type": "constant", + "label": "orc_latency_threshold_ms", + "value": "60000", + "description": "" + }, + { + "name": "VAR_AIO_DP_ERROR_THRESHOLD", + "type": "constant", + "label": "aio_dp_error_threshold", + "value": "20", + "description": "" + }, + { + "name": "VAR_AIO_DP_NATS_UTILIZATION_THRESHOLD", + "type": "constant", + "label": "aio_dp_nats_utilization_threshold", + "value": "0.90", + "description": "" + }, + { + "name": "VAR_AIO_DP_ERROR_RATE", + "type": "constant", + "label": "aio_dp_error_rate", + "value": "0.05", + "description": "" + }, + { + "name": "VAR_AIO_DP_LATENCY_THRESHOLD_MS", + "type": "constant", + "label": "aio_dp_latency_threshold_ms", + "value": "5000", + "description": "" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "state-timeline", + "name": "State timeline", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 64, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n Azure IoT Operations\n
\n
\n Health Model\n
", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "transparent": true, + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 8, + "x": 0, + "y": 3 + }, + "id": 2, + "maxPerRow": 12, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n ${cluster} \n
\n\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "repeat": "cluster", + "repeatDirection": "h", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "transparent": true, + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 55, + "lineWidth": 0, + "spanNulls": false + }, + "mappings": [], + "max": 1, + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "blue", + "value": null + }, + { + "color": "purple", + "value": 0 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 0, + "y": 5 + }, + "id": 39, + "maxPerRow": 12, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": true, + "rowHeight": 0.5, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.5.12", + "repeat": "cluster", + "repeatDirection": "h", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count by(chartversion) (count by(chartversion) (aio_orc_controller_reconcile_latency_count{cluster=~\"$cluster\"}))", + "format": "time_series", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "AIO Version", + "transparent": true, + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 82, + "lineWidth": 0, + "spanNulls": false + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#505050", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + }, + { + "color": "#7f7f7f", + "value": 404 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "MessageQueue SLO" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Click for details on ${__field.labels._}", + "url": "/d/e2e98c97-7655-44d1-b8f3-5008b7f6ffbb/aio-health-service-mq?${__all_variables}&${__url_time_range}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "DataProcessor SLO" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Click for details on ${__field.labels._}", + "url": "/d/e7f4802e-d73b-4f06-a84c-715cdc42fb35/aio-health-service-dp?${__all_variables}&${__url_time_range}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "OPCUA SLO" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Click for details on ${__field.labels._}", + "url": "/d/ba43ff7a-e741-4965-b430-c9d4bf1757a6/aio-health-service-opcua?${__all_variables}&${__url_time_range}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Data Processor SLO" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Click for details on ${__field.labels._}", + "url": "/d/e7f4802e-d73b-4f06-a84c-715cdc42fb35/aio-health-service-dp?${__all_variables}&${__url_time_range}" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 8 + }, + "id": 33, + "maxPerRow": 12, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": true, + "rowHeight": 0.72, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "repeat": "cluster", + "repeatDirection": "h", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(min(\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(\r\n # Raw Success Rate for MQTT message publishing by app, qos, and opc-ua connector\r\n label_replace(min by(app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_mqtt_message_publishing_duration_count{cluster=\"$cluster\",aio_opc_mqtt_publish_result=\"success\"}[5m:1m])\r\n * 100 / rate(aio_opc_mqtt_message_publishing_duration_count{cluster=\"$cluster\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_module_name\",\"(.*)\"))\r\n ,\"_\",\"MQTT Publishing Success Rate\",\"\",\"\")\r\n >= $opc_slo_sr_goal) or\r\n 0 * sgn(\r\n # Raw Success Rate for MQTT message publishing by app, qos, and opc-ua connector\r\n label_replace(min by(app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_mqtt_message_publishing_duration_count{cluster=\"$cluster\",aio_opc_mqtt_publish_result=\"success\"}[5m:1m])\r\n * 100 / rate(aio_opc_mqtt_message_publishing_duration_count{cluster=\"$cluster\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_module_name\",\"(.*)\"))\r\n ,\"_\",\"MQTT Publishing Success Rate\",\"\",\"\")\r\n < $opc_slo_sr_goal) or\r\n vector(0)>0\r\n ) or vector(0))\r\n ,\"url\",\"/d/_dMuZUh4kd/opc-ua-broker-dashboard\",\"\",\"\")\r\n ,\"_\",\"MQTT Publishing Success Rate\",\"\",\"\") or\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(\r\n label_replace(min by(app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_session_connect_duration_count{cluster=\"$cluster\",aio_opc_module_type=\"opcua-connector\",aio_opc_connect_result=\"succeeded\"}[5m:1m])\r\n * 100 / rate(aio_opc_session_connect_duration_count{cluster=\"$cluster\",aio_opc_module_type=\"opcua-connector\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_module_name\",\"(.*)\"))\r\n ,\"_\",\"OPC-UA Connect Success Rate\",\"\",\"\")\r\n >= $opc_slo_sr_goal) or\r\n 0 * sgn(\r\n label_replace(min by(app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_session_connect_duration_count{cluster=\"$cluster\",aio_opc_module_type=\"opcua-connector\",aio_opc_connect_result=\"succeeded\"}[5m:1m])\r\n * 100 / rate(aio_opc_session_connect_duration_count{cluster=\"$cluster\",aio_opc_module_type=\"opcua-connector\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_module_name\",\"(.*)\"))\r\n ,\"_\",\"OPC-UA Connect Success Rate\",\"\",\"\")\r\n < $opc_slo_sr_goal) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"/d/_dMuZUh4kd/opc-ua-broker-dashboard\",\"\",\"\")\r\n ,\"_\",\"OPC UA Connect Success Rate\",\"\",\"\") or\r\n\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(\r\n # Raw Latency for MQTT Publishing\r\n label_replace(\r\n histogram_quantile(0.95,sum by(le,app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",aio_opc_module_type=\"opcua-connector\",aio_opc_mqtt_publish_result=\"success\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_module_name\",\"(.*)\")))\r\n ,\"_\",\"MQTT Publishing P95 Latency\",\"\",\"\") \r\n <= $opc_slo_publish_latency_ms_goal) or\r\n 0.5 * sgn(\r\n # Raw Latency for MQTT Publishing\r\n label_replace(\r\n histogram_quantile(0.95,sum by(le,app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",aio_opc_module_type=\"opcua-connector\",aio_opc_mqtt_publish_result=\"success\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_module_name\",\"(.*)\")))\r\n ,\"_\",\"MQTT Publishing P95 Latency\",\"\",\"\") \r\n > $opc_slo_publish_latency_ms_goal) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"/d/_dMuZUh4kd/opc-ua-broker-dashboard\",\"\",\"\")\r\n ,\"_\",\"MQTT Publishing latency\",\"\",\"\") or \r\n\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(\r\n #Raw latency for OPC UA Connect by app and opc-ua connector\r\n label_replace(\r\n histogram_quantile(0.95,sum by(le,app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_session_connect_duration_bucket{cluster=\"$cluster\",aio_opc_module_type=\"opcua-connector\",aio_opc_connect_result=\"succeeded\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_module_name\",\"(.*)\")))\r\n ,\"_\",\"OPC-UA Connect P95 Latency\",\"\",\"\")\r\n <= $opc_slo_connect_latency_ms_goal) or\r\n 0 * sgn(\r\n #Raw latency for OPC UA Connect by app and opc-ua connector\r\n label_replace(\r\n histogram_quantile(0.95,sum by(le,app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_session_connect_duration_bucket{cluster=\"$cluster\",aio_opc_module_type=\"opcua-connector\",aio_opc_connect_result=\"succeeded\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_module_name\",\"(.*)\")))\r\n ,\"_\",\"OPC-UA Connect P95 Latency\",\"\",\"\")\r\n > $opc_slo_connect_latency_ms_goal) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"/d/_dMuZUh4kd/opc-ua-broker-dashboard\",\"\",\"\")\r\n ,\"_\",\"OPC-UA Connect latency\",\"\",\"\") or \r\n #######################################################################################################################################\r\n # OLD E4I SLO HEALTH:\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(\r\n # Raw Success Rate for MQTT message publishing by app, qos, and opc-ua connector\r\n label_replace(min by(app,opc_ua_connector)(label_replace(label_replace(\r\n rate(e4i_mqtt_message_publishing_duration_count{cluster=\"$cluster\",e4i_module_type=\"opc-ua-connector\",e4i_mqtt_publish_result=\"success\"}[5m:1m])\r\n * 100 / rate(e4i_mqtt_message_publishing_duration_count{cluster=\"$cluster\",e4i_module_type=\"opc-ua-connector\"}[5m:1m])\r\n ,\"app\",\"$1\",\"e4i_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"e4i_module_name\",\"(.*)\"))\r\n ,\"_\",\"MQTT Publishing Success Rate\",\"\",\"\")\r\n >= $opc_slo_sr_goal) or\r\n 0 * sgn(\r\n # Raw Success Rate for MQTT message publishing by app, qos, and opc-ua connector\r\n label_replace(min by(app,opc_ua_connector)(label_replace(label_replace(\r\n rate(e4i_mqtt_message_publishing_duration_count{cluster=\"$cluster\",e4i_module_type=\"opc-ua-connector\",e4i_mqtt_publish_result=\"success\"}[5m:1m])\r\n * 100 / rate(e4i_mqtt_message_publishing_duration_count{cluster=\"$cluster\",e4i_module_type=\"opc-ua-connector\"}[5m:1m])\r\n ,\"app\",\"$1\",\"e4i_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"e4i_module_name\",\"(.*)\"))\r\n ,\"_\",\"MQTT Publishing Success Rate\",\"\",\"\")\r\n < $opc_slo_sr_goal) or\r\n vector(0)>0\r\n ) or vector(0))\r\n ,\"url\",\"/d/_dMuZUh4kd/opc-ua-broker-dashboard\",\"\",\"\")\r\n ,\"_\",\"MQTT Publishing Success Rate\",\"\",\"\") or\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(\r\n label_replace(min by(app,opc_ua_connector)(label_replace(label_replace(\r\n rate(e4i_opc_session_connect_duration_count{cluster=\"$cluster\",e4i_module_type=\"opc-ua-connector\",e4i_opc_connect_result=\"succeeded\"}[5m:1m])\r\n * 100 / rate(e4i_opc_session_connect_duration_count{cluster=\"$cluster\",e4i_module_type=\"opc-ua-connector\"}[5m:1m])\r\n ,\"app\",\"$1\",\"e4i_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"e4i_module_name\",\"(.*)\"))\r\n ,\"_\",\"OPC-UA Connect Success Rate\",\"\",\"\")\r\n >= $opc_slo_sr_goal) or\r\n 0 * sgn(\r\n label_replace(min by(app,opc_ua_connector)(label_replace(label_replace(\r\n rate(e4i_opc_session_connect_duration_count{cluster=\"$cluster\",e4i_module_type=\"opc-ua-connector\",e4i_opc_connect_result=\"succeeded\"}[5m:1m])\r\n * 100 / rate(e4i_opc_session_connect_duration_count{cluster=\"$cluster\",e4i_module_type=\"opc-ua-connector\"}[5m:1m])\r\n ,\"app\",\"$1\",\"e4i_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"e4i_module_name\",\"(.*)\"))\r\n ,\"_\",\"OPC-UA Connect Success Rate\",\"\",\"\")\r\n < $opc_slo_sr_goal) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"/d/_dMuZUh4kd/opc-ua-broker-dashboard\",\"\",\"\")\r\n ,\"_\",\"OPC UA Connect Success Rate\",\"\",\"\") or\r\n\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(\r\n # Raw Latency for MQTT Publishing\r\n label_replace(\r\n histogram_quantile(0.95,sum by(le,app,opc_ua_connector)(label_replace(label_replace(\r\n rate(e4i_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",e4i_module_type=\"opc-ua-connector\",e4i_mqtt_publish_result=\"success\"}[5m:1m])\r\n ,\"app\",\"$1\",\"e4i_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"e4i_module_name\",\"(.*)\")))\r\n ,\"_\",\"MQTT Publishing P95 Latency\",\"\",\"\") \r\n <= $opc_slo_publish_latency_ms_goal) or\r\n 0 * sgn(\r\n # Raw Latency for MQTT Publishing\r\n label_replace(\r\n histogram_quantile(0.95,sum by(le,app,opc_ua_connector)(label_replace(label_replace(\r\n rate(e4i_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",e4i_module_type=\"opc-ua-connector\",e4i_mqtt_publish_result=\"success\"}[5m:1m])\r\n ,\"app\",\"$1\",\"e4i_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"e4i_module_name\",\"(.*)\")))\r\n ,\"_\",\"MQTT Publishing P95 Latency\",\"\",\"\") \r\n > $opc_slo_publish_latency_ms_goal) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"/d/_dMuZUh4kd/opc-ua-broker-dashboard\",\"\",\"\")\r\n ,\"_\",\"MQTT Publishing latency\",\"\",\"\") or \r\n\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(\r\n #Raw latency for OPC UA Connect by app and opc-ua connector\r\n label_replace(\r\n histogram_quantile(0.95,sum by(le,app,opc_ua_connector)(label_replace(label_replace(\r\n rate(e4i_opc_session_connect_duration_bucket{cluster=\"$cluster\",e4i_module_type=\"opc-ua-connector\",e4i_opc_connect_result=\"succeeded\"}[5m:1m])\r\n ,\"app\",\"$1\",\"e4i_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"e4i_module_name\",\"(.*)\")))\r\n ,\"_\",\"OPC-UA Connect P95 Latency\",\"\",\"\")\r\n <= $opc_slo_connect_latency_ms_goal) or\r\n 0 * sgn(\r\n #Raw latency for OPC UA Connect by app and opc-ua connector\r\n label_replace(\r\n histogram_quantile(0.95,sum by(le,app,opc_ua_connector)(label_replace(label_replace(\r\n rate(e4i_opc_session_connect_duration_bucket{cluster=\"$cluster\",e4i_module_type=\"opc-ua-connector\",e4i_opc_connect_result=\"succeeded\"}[5m:1m])\r\n ,\"app\",\"$1\",\"e4i_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"e4i_module_name\",\"(.*)\")))\r\n ,\"_\",\"OPC-UA Connect P95 Latency\",\"\",\"\")\r\n > $opc_slo_connect_latency_ms_goal) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"/d/_dMuZUh4kd/opc-ua-broker-dashboard\",\"\",\"\")\r\n ,\"_\",\"OPC-UA Connect latency\",\"\",\"\") or \r\n vector(0)>0\r\n),\"_\",\"OPCUA SLO\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "OPC" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(min(\r\n label_replace(label_replace(\r\n (1 - min(\r\n 1 * sgn(\r\n sum(\r\n rate(aio_mq_authentication_failures{cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])\r\n )\r\n <= 20) or\r\n 0 * sgn(\r\n sum(\r\n rate(aio_mq_authentication_failures{cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])\r\n )\r\n > 20)) or vector(404))\r\n ,\"url\",\"/d/f5a5c523-2cb6-42d8-b23f-06b0227fe40b/e4k-connect\",\"\",\"\")\r\n ,\"_\",\"Authentication failures\",\"\",\"\") or\r\n label_replace(label_replace(\r\n (1 - min(\r\n 1 * sgn(\r\n sum(\r\n rate(aio_mq_authorization_deny{cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])\r\n )\r\n <= 20) or\r\n 0 * sgn(\r\n sum(\r\n rate(aio_mq_authorization_deny{cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])\r\n )\r\n > 20)) or vector(404))\r\n ,\"url\",\"/d/f5a5c523-2cb6-42d8-b23f-06b0227fe40b/e4k-connect\",\"\",\"\")\r\n ,\"_\",\"Authorization failures\",\"\",\"\") or \r\n label_replace(label_replace(\r\n (1 - min(\r\n 1 * sgn(\r\n sum(rate(aio_mq_backpressure_packets_rejected{pod_type=\"BE\", cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])) / \r\n sum(quantile_over_time(.95, rate(aio_mq_publishes_received{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[2m])[30m:]))\r\n <= 0.05) or\r\n 0 * sgn(\r\n sum(rate(aio_mq_backpressure_packets_rejected{pod_type=\"BE\", cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])) / \r\n sum(quantile_over_time(.95, rate(aio_mq_publishes_received{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[2m])[30m:]))\r\n <= 0.05)) or vector(404))\r\n ,\"url\",\"/d/E19etH24z/e4k-cluster-perf\",\"\",\"\")\r\n ,\"_\",\"Backpressure\",\"\",\"\") or\r\n # OLD E4K SLOs:\r\n label_replace(label_replace(\r\n (1 - min(\r\n 1 * sgn(\r\n sum(\r\n rate(e4k_authentication_failures{cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])\r\n )\r\n <= 20) or\r\n 0 * sgn(\r\n sum(\r\n rate(e4k_authentication_failures{cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])\r\n )\r\n > 20)) or vector(404))\r\n ,\"url\",\"/d/f5a5c523-2cb6-42d8-b23f-06b0227fe40b/e4k-connect\",\"\",\"\")\r\n ,\"_\",\"Authentication failures\",\"\",\"\") or\r\n label_replace(label_replace(\r\n (1 - min(\r\n 1 * sgn(\r\n sum(\r\n rate(e4k_authorization_deny{cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])\r\n )\r\n <= 20) or\r\n 0 * sgn(\r\n sum(\r\n rate(e4k_authorization_deny{cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])\r\n )\r\n > 20)) or vector(404))\r\n ,\"url\",\"/d/f5a5c523-2cb6-42d8-b23f-06b0227fe40b/e4k-connect\",\"\",\"\")\r\n ,\"_\",\"Authorization failures\",\"\",\"\") or \r\n label_replace(label_replace(\r\n (1 - min(\r\n 1 * sgn(\r\n sum(rate(e4k_backpressure_packets_rejected{pod_type=\"BE\", cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])) / \r\n sum(quantile_over_time(.95, rate(e4k_publishes_received{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[2m])[30m:]))\r\n <= 0.05) or\r\n 0 * sgn(\r\n sum(rate(e4k_backpressure_packets_rejected{pod_type=\"BE\", cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])) / \r\n sum(quantile_over_time(.95, rate(e4k_publishes_received{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[2m])[30m:]))\r\n <= 0.05)) or vector(404))\r\n ,\"url\",\"/d/E19etH24z/e4k-cluster-perf\",\"\",\"\")\r\n ,\"_\",\"Backpressure\",\"\",\"\") or\r\n vector(0) > 0 # Tail; not shown\r\n),\"_\",\"MessageQueue SLO\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "MQ" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(min(\r\n label_replace(\r\n (\r\n 1 - min(\r\n sgn(sum(rate(aio_dp_stage_errors{cluster=~\"$cluster\"}[$__rate_interval])) <= $aio_dp_error_threshold)\r\n or\r\n sgn(sum(rate(aio_dp_reader_errors{cluster=~\"$cluster\"}[$__rate_interval])) <= $aio_dp_error_threshold)\r\n )\r\n or vector(1)\r\n )\r\n ,\"_\",\"Errors\",\"\",\"\") \r\n or\r\n label_replace(\r\n (\r\n sgn(\r\n (\r\n sum(rate(aio_dp_reader_errors{cluster=\"$cluster\"}[$__rate_interval])) + \r\n sum(rate(aio_dp_stage_errors{cluster=\"$cluster\"}[$__rate_interval]))\r\n ) / \r\n (\r\n sum(rate(aio_dp_reader_incoming_messages{cluster=\"$cluster\"}[$__rate_interval])) + \r\n sum(rate(aio_dp_stage_incoming_messages{cluster=\"$cluster\"}[$__rate_interval]))\r\n ) < $aio_dp_error_rate\r\n )\r\n or vector(1)\r\n )\r\n ,\"_\",\"Success Rate\",\"\",\"\")\r\n or\r\n label_replace(\r\n (min(\r\n sgn(\r\n max(\r\n histogram_quantile(0.95, rate(aio_dp_pipeline_latency_bucket{cluster=~\"$cluster\"}[$__rate_interval]))\r\n ) < $aio_dp_latency_threshold_ms\r\n )\r\n or\r\n 1 - sgn(\r\n max(\r\n histogram_quantile(0.95, rate(aio_dp_pipeline_latency_bucket{cluster=~\"$cluster\"}[$__rate_interval]))\r\n ) >= $aio_dp_latency_threshold_ms\r\n )\r\n ) \r\n or vector(404))\r\n ,\"_\",\"Pipeline Latency\",\"\",\"\")\r\n or \r\n label_replace(\r\n (\r\n min(\r\n sgn(\r\n sum(rate(aio_dp_reader_processed_heartbeats{cluster=~\"$cluster\"}[$__rate_interval]))\r\n >= sum(rate(aio_dp_reader_incoming_heartbeats{cluster=~\"$cluster\"}[$__rate_interval]))\r\n )\r\n or\r\n sgn(\r\n sum(rate(aio_dp_stage_heartbeats{cluster=~\"$cluster\"}[$__rate_interval]))\r\n >= sum(rate(aio_dp_reader_processed_heartbeats{cluster=~\"$cluster\"}[$__rate_interval]))\r\n )\r\n )\r\n or vector(404))\r\n ,\"_\",\"Heartbeats\",\"\",\"\")\r\n or\r\n label_replace(\r\n (\r\n sgn(\r\n sum by(server_id)(nats_varz_jetstream_stats_storage{cluster=~\"$cluster\"}) > 0\r\n and\r\n (sum by(server_id)(nats_varz_jetstream_stats_storage{cluster=~\"$cluster\"}) / \r\n sum by(server_id)(nats_varz_jetstream_config_max_storage{cluster=~\"$cluster\"}))\r\n <= $aio_dp_nats_utilization_threshold\r\n )\r\n or vector(404))\r\n ,\"_\",\"Message Store\",\"\",\"\")\r\n),\"_\",\"DataProcessor SLO\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "DP" + } + ], + "title": "Scenario Health", + "transformations": [], + "transparent": true, + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 82, + "lineWidth": 0, + "spanNulls": false + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#505050", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + }, + { + "color": "#7f7f7f", + "value": 404 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "MessageQueue Health" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Click for details on ${__field.labels._}", + "url": "/d/e2e98c97-7655-44d1-b8f3-5008b7f6ffbb/aio-health-service-mq?${__all_variables}&${__url_time_range}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "DataProcessor Health" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Click for details on ${__field.labels._}", + "url": "/d/e7f4802e-d73b-4f06-a84c-715cdc42fb35/aio-health-service-dp?${__all_variables}&${__url_time_range}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "OPCUA Health" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Click for details on ${__field.labels._}", + "url": "/d/ba43ff7a-e741-4965-b430-c9d4bf1757a6/aio-health-service-opcua?${__all_variables}&${__url_time_range}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Orchestration Health" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Click for details on ${__field.labels._}", + "url": "/d/f42af83d-1bfe-4bdd-966b-ff1886fee8c6/aio-health-service-orch?${__all_variables}&${__url_time_range}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Akri Health" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Click for details on ${__field.labels._}", + "url": "/d/df11b4b1-2dcb-4e6b-af47-4c9fc5793f56/aio-health-service-akri?${__all_variables}&${__url_time_range}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "DataProcessor Health" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Click for details on ${__field.labels._}", + "url": "/d/e7f4802e-d73b-4f06-a84c-715cdc42fb35/aio-health-service-dp?${__all_variables}&${__url_time_range}" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 12 + }, + "id": 1, + "maxPerRow": 12, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": true, + "rowHeight": 0.72, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "repeat": "cluster", + "repeatDirection": "h", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(min(\r\navg(label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n label_replace(label_join(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"^aio-akri-agent.*\"} or\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"^aio-akri-agent.*\"} or\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"^aio-akri-agent.*\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n /\r\n label_replace(label_join(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"^aio-akri-agent.*\"} or\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"^aio-akri-agent.*\"} or\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"^aio-akri-agent.*\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n) by (workload) >=0 \r\n) or vector(-1),\"_\",\"Akri Health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "AKRI" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(min(\r\n label_replace(label_replace(\r\n (min(\r\n label_replace(aio_mq_ping_correctness{cluster=~\"$cluster\"},\"depHealth\",\"ping\",\"\",\"\") or\r\n label_replace(aio_mq_publish_route_replication_correctness{cluster=~\"$cluster\"},\"depHealth\",\"publish\",\"\",\"\") or\r\n label_replace(aio_mq_subscribe_route_replication_correctness{cluster=~\"$cluster\"},\"depHealth\",\"subscribe\",\"\",\"\") or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"/d/e2e98c97-7655-44d1-b8f3-5008b7f6ffbb/aio-health-service-mq\",\"\",\"\")\r\n ,\"_\",\"Self-test input (MQ)\",\"\",\"\") or\r\n label_replace(\r\n (min(\r\n 0 * sgn(0 < round(sum(increase(aio_dp_stage_errors{cluster=~\"$cluster\",cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}[$__rate_interval])))) or\r\n 1 * sgn(aio_dp_stage_incoming_messages{cluster=~\"$cluster\", stage_type=~\"output/.*\", cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"Self-test stage errors\",\"\",\"\") or\r\n label_replace(\r\n (min(sgn(rate(\r\n aio_dp_stage_incoming_messages{cluster=~\"$cluster\", stage_type=~\"output/.*\", cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}[$__rate_interval]\r\n )*60)) or vector(-1))\r\n ,\"_\",\"Self-test output\",\"\",\"\") or\r\n label_replace(\r\n (min(\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_dp_pipeline_latency_bucket{cluster=~\"$cluster\",cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}[5m]\r\n ))) < $aio_dp_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_dp_pipeline_latency_bucket{cluster=~\"$cluster\",cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}[5m]\r\n ))) >= $aio_dp_latency_threshold_ms) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"Self-test pipeline latency\",\"\",\"\") or \r\n label_replace(label_replace(\r\n (min(\r\n 0 * sgn(max(\r\n 100 * sum by(server_id)(nats_varz_jetstream_stats_storage{cluster=~\"$cluster\"})\r\n / sum by(server_id)(nats_varz_jetstream_config_max_storage{cluster=~\"$cluster\"})\r\n ) > 90) or\r\n 1 * sgn(max(\r\n 100 * sum by(server_id)(nats_varz_jetstream_stats_storage{cluster=~\"$cluster\"})\r\n / sum by(server_id)(nats_varz_jetstream_config_max_storage{cluster=~\"$cluster\"})\r\n ) <= 90) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"/d/e17d0b7f-9771-4cb8-adf9-56cbaef3fff6/aio-service-dp-messagestore\",\"\",\"\")\r\n ,\"_\",\"Store Utilization\",\"\",\"\") or \r\n vector(0)>0\r\n),\"_\",\"DataProcessor Health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "DP" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(min(\r\n label_replace(label_replace((\r\n min(aio_mq_ping_correctness{cluster=~\"$cluster\"}) or vector(404))\r\n ,\"url\",\"/d/f46e5384-d78d-480a-911c-0328cb20b224/e4k-ping\",\"\",\"\")\r\n ,\"_\",\"Ping health\",\"\",\"\") or\r\n label_replace(label_replace((\r\n min(aio_mq_publish_route_replication_correctness{cluster=~\"$cluster\"}) or vector(404))\r\n ,\"url\",\"/d/THdxxxh4z/e4k-publish\",\"\",\"\")\r\n ,\"_\",\"Publish health\",\"\",\"\") or \r\n label_replace(label_replace((\r\n min(aio_mq_subscribe_route_replication_correctness{cluster=~\"$cluster\"}) or vector(404))\r\n ,\"url\",\"/d/d0318b5a-4afa-47e3-975f-6b1d2d783849/e4k-subscribe\",\"\",\"\")\r\n ,\"_\",\"Subscribe health\",\"\",\"\") or \r\n # OLD E4K METRICS:\r\n label_replace(label_replace((\r\n min(ping_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}) or \r\n min(e4k_ping_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}) or vector(404))\r\n ,\"url\",\"/d/f46e5384-d78d-480a-911c-0328cb20b224/e4k-ping\",\"\",\"\")\r\n ,\"_\",\"Ping health\",\"\",\"\") or\r\n label_replace(label_replace((\r\n min(publish_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}) or \r\n min(e4k_publish_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}) or vector(404))\r\n ,\"url\",\"/d/THdxxxh4z/e4k-publish\",\"\",\"\")\r\n ,\"_\",\"Publish health\",\"\",\"\") or \r\n label_replace(label_replace((\r\n min(subscribe_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}) or \r\n min(e4k_subscribe_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}) or vector(404))\r\n ,\"url\",\"/d/d0318b5a-4afa-47e3-975f-6b1d2d783849/e4k-subscribe\",\"\",\"\")\r\n ,\"_\",\"Subscribe health\",\"\",\"\") or \r\n vector(0) > 0 # Tail; not shown\r\n),\"_\",\"MessageQueue Health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "MQ" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(min(\r\n label_replace(\r\n (min(\r\n 1 * sgn(\r\n 100*sum(rate(aio_opc_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\",aio_opc_mqtt_publish_result=\"Success\"}[$__rate_interval]))\r\n / sum(rate(aio_opc_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\"}[$__rate_interval]))\r\n > 99) or\r\n 0 * sgn(sum(rate(aio_opc_mqtt_message_publishing_duration_count{cluster=\"$cluster\",service_name=\"supervisor\"}[$__rate_interval])) > 0) or\r\n vector(0)>0\r\n ) or vector(-1))\r\n #,\"url\",\"/d/f46e5384-d78d-480a-911c-0328cb20b224/e4k-ping\",\"\",\"\")\r\n ,\"_\",\"Supervisor Success Rate\",\"\",\"\") or\r\n label_replace(\r\n (min(\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_opc_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n ))) < $aio_opc_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_opc_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n ))) >= $aio_opc_latency_threshold_ms) or\r\n vector(0)>0\r\n ) or vector(404))\r\n #,\"url\",\"/d/f5a5c523-2cb6-42d8-b23f-06b0227fe40b/e4k-connect\",\"\",\"\")\r\n ,\"_\",\"Supervisor latency\",\"\",\"\") or \r\n # OLD METRIC NAMES BELOW - TO BE REMOVED:\r\n label_replace(\r\n (min(\r\n 1 * sgn(\r\n 100*sum(rate(e4i_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\",e4i_mqtt_publish_result=\"Success\"}[$__rate_interval]))\r\n / sum(rate(e4i_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\"}[$__rate_interval]))\r\n > 99) or\r\n 0 * sgn(sum(rate(e4i_mqtt_message_publishing_duration_count{cluster=\"$cluster\",service_name=\"supervisor\"}[$__rate_interval])) > 0) or\r\n vector(0)>0\r\n ) or vector(-1))\r\n #,\"url\",\"/d/f46e5384-d78d-480a-911c-0328cb20b224/e4k-ping\",\"\",\"\")\r\n ,\"_\",\"Supervisor Success Rate\",\"\",\"\") or\r\n label_replace(\r\n (min(\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n e4i_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n ))) < $aio_opc_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n e4i_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n ))) >= $aio_opc_latency_threshold_ms) or\r\n vector(0)>0\r\n ) or vector(404))\r\n #,\"url\",\"/d/f5a5c523-2cb6-42d8-b23f-06b0227fe40b/e4k-connect\",\"\",\"\")\r\n ,\"_\",\"Supervisor latency\",\"\",\"\") or \r\n vector(0)>0\r\n),\"_\",\"OPCUA Health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "OPCUA" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(min(\r\n label_replace(#label_replace(\r\n (min(\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_orc_api_operation_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) < $orc_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_orc_api_operation_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) >= $orc_latency_threshold_ms) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"Self-test API Operation latency\",\"\",\"\") or\r\n label_replace(#label_replace(\r\n (min(\r\n 0 * sgn(0 < round(sum(increase(aio_orc_api_operation_errors{cluster=~\"$cluster\"}[$__rate_interval])))) or\r\n 1 * sgn(aio_orc_api_operation_latency_count{cluster=~\"$cluster\"}) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"Self-test API Operation errors\",\"\",\"\") or\r\n label_replace(#label_replace(\r\n (min(\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_orc_api_operation_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) < $orc_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_orc_api_operation_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) >= $orc_latency_threshold_ms) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"Self-test Provider Operation latency\",\"\",\"\") or\r\n label_replace(#label_replace(\r\n (min(\r\n 0 * sgn(0 < round(sum(increase(aio_orc_provider_operation_errors{cluster=~\"$cluster\"}[$__rate_interval])))) or\r\n 1 * sgn(aio_orc_provider_operation_latency_count{cluster=~\"$cluster\"}) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"Self-test Provider Operation errors\",\"\",\"\") or\r\n # OLD SYMPHONY METRICS - TO BE REMOVED\r\n label_replace(#label_replace(\r\n (min(\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n symphony_api_operation_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) < $orc_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n symphony_api_operation_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) >= $orc_latency_threshold_ms) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"Self-test API Operation latency\",\"\",\"\") or\r\n label_replace(#label_replace(\r\n (min(\r\n 0 * sgn(0 < round(sum(increase(symphony_api_operation_errors{cluster=~\"$cluster\"}[$__rate_interval])))) or\r\n 1 * sgn(symphony_api_operation_latency_count{cluster=~\"$cluster\"}) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"Self-test API Operation errors\",\"\",\"\") or\r\n label_replace(#label_replace(\r\n (min(\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n symphony_api_operation_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) < $orc_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n symphony_api_operation_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) >= $orc_latency_threshold_ms) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"Self-test Provider Operation latency\",\"\",\"\") or\r\n label_replace(#label_replace(\r\n (min(\r\n 0 * sgn(0 < round(sum(increase(symphony_provider_operation_errors{cluster=~\"$cluster\"}[$__rate_interval])))) or\r\n 1 * sgn(symphony_provider_operation_latency_count{cluster=~\"$cluster\"}) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"Self-test Provider Operation errors\",\"\",\"\") or\r\n vector(0)>0\r\n),\"_\",\"Orchestration Health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "ORC" + } + ], + "title": "Service Health", + "transformations": [], + "transparent": true, + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "Click for more details (health-infra-workload)", + "url": "/d/E5cCeHj4z/health-infra-workload?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 17 + }, + "id": 9, + "links": [ + { + "targetBlank": true, + "title": "Click for more details (health-infra-workload)", + "url": "/d/E5cCeHj4z/health-infra-workload?${__all_variables}&${__url_time_range}" + }, + { + "targetBlank": true, + "title": "Open K8s / Compute Resources / Namespace (Workloads)", + "url": "/d/a87fb0d919ec0ea5f6543124e16c6738/kubernetes-compute-resources-namespace-workloads?${cluster:queryparam}&${__url_time_range}" + } + ], + "maxPerRow": 12, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.9, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "repeat": "cluster", + "repeatDirection": "h", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Workload Readiness health\r\n############################\r\nlabel_replace(min(\r\navg(label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n label_replace(label_join(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace\"} or\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\"$namespacem\"} or\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n / label_replace(label_join(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\"$namespace\"} or\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\"$namespace\"} or\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\"$namespace\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n) by (workload) >=0 \r\n) or vector(0),\"_\",\"AIO Workload Readiness\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Restart Health:\r\n############################\r\nlabel_replace(\r\n sgn(sum_over_time(sum(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\"$namespace\"}[10m:1m]\r\n )*60)[1h:]) > 5) * 0.0 # RED: Cumulative restarts over X(5) time greater than Y(1h)\r\n or (max(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\"$namespace\"}[5m:1m]\r\n )*60*5) > 0) * 0.5 # YELLOW: restarts detected but below Red threshold\r\n or sgn(max(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\"$namespace\"}\r\n + 1 >= 0))\r\n #or vector(1) # Healthy\r\n ,\"_\",\"AIO Container Restarts\",\"\",\"\")\r\n## uncomment below to t-shoot this health metric\r\n# or label_replace(sum_over_time(sum(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[10m:1m])*60)[1h:]),\"_\",\"Total-restarts-over-time\",\"\",\"\")\r\n# or label_replace((max(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[5m:1m])*60*5) without (__name__,uid,instance,job) > 0),\"_\",\"restart\",\"\",\"\") # Base query for counting restarts\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container CPU top-level health\r\n################################\r\nlabel_replace(\r\nmin(sgn( # Check for throttling > N indicating container is exceeding its CPU limits\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\"$namespace\",container!=\"\"}[10m]) \r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\"$namespace\",container!=\"\"}[10m])\r\n >= 0.60) # If throttle create is greater than this percentage, we'll multiply sgn by 0.5 to show as error (or warning depending on threshold coloring)\r\n ) # by (namespace,container) # These are commented out for top-level\r\n * 0.0\r\nor\r\nmin(sgn( # Check for throttling > N indicating container is exceeding its CPU limits\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\"$namespace\",container!=\"\"}[10m]) \r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\"$namespace\",container!=\"\"}[10m])\r\n >= 0.40) # If throttle create is greater than this percentage, we'll multiply sgn by 0.5 to show as error (or warning depending on threshold coloring)\r\n ) # by (namespace,container) # These are commented out for top-level\r\n * 0.5\r\nor\r\nmin( # Check to see if container is missing CPU Limits configuration\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace\",container!=\"\",resource=\"cpu\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace\",container!=\"\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n ) #by (namespace,container) # These are commented out for top-level\r\n,\"_\",\"AIO Container CPU\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Memory Health:\r\n###########################\r\nlabel_replace(\r\nmin( # Look for high memory utilization\r\n 0.0 * sgn((\r\n max(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\"$namespace\",container!=\"\"}) by (namespace,container)\r\n / min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace\",container!=\"\",resource=\"memory\"}) by (namespace, container)\r\n ) >= .95) or # show health state of 0 if container memory utilization >= 95%\r\n 0.5 * sgn((\r\n max(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\"$namespace\",container!=\"\"}) by (namespace,container)\r\n / min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace\",container!=\"\",resource=\"memory\"}) by (namespace, container)\r\n ) >= .80) or # show health state of 0.5 if container memory utilization >= 80%\r\n vector(0)>0\r\n) #by (container) \r\nor\r\nmin( # Look for missing limits which we will show as 0 if missing\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace\",container!=\"\",resource=\"memory\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\"$namespace\",container!=\"\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n) #by (container) \r\n,\"_\",\"AIO Container Memory\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Kubernetes Workload Health", + "transformations": [], + "transparent": true, + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "Click for more details", + "url": "/d/E5cCeHj4z/health-infra-workload?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-blue", + "value": null + }, + { + "color": "semi-dark-blue", + "value": 0.1 + }, + { + "color": "blue", + "value": 0.2 + }, + { + "color": "light-blue", + "value": 0.3 + }, + { + "color": "super-light-blue", + "value": 0.4 + }, + { + "color": "super-light-blue", + "value": 0.5 + }, + { + "color": "super-light-purple", + "value": 0.6 + }, + { + "color": "light-purple", + "value": 0.7 + }, + { + "color": "purple", + "value": 0.8 + }, + { + "color": "semi-dark-purple", + "value": 0.9 + }, + { + "color": "dark-purple", + "value": 0.95 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 0, + "y": 21 + }, + "id": 16, + "maxPerRow": 12, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.8, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "repeat": "cluster", + "repeatDirection": "h", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace( max(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace\",container=\"\",cpu=\"total\"}[5m:1m])) /\r\n max_over_time(max(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace\",container=\"\",cpu=\"total\"}[5m:1m]))[$__range:])\r\n ,\"_\",\"CPU Relative Heatmap\",\"\",\"\")\r\nor label_replace(max(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\"$namespace\",container=\"\"}) /\r\n max_over_time(max(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\"$namespace\",container=\"\"})[$__range:])\r\n ,\"_\",\"Memory Relative Heatmap\",\"\",\"\")", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Kubernetes Workload Usage ", + "transformations": [], + "transparent": true, + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "Click for more details (health-infra-cluster)", + "url": "/d/e159191f-81f2-4443-af47-fe7cd4da23f8/health-infra-cluster?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#808080", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 24 + }, + "id": 14, + "links": [ + { + "targetBlank": true, + "title": "Click for more details (health-infra-cluster)", + "url": "/d/e159191f-81f2-4443-af47-fe7cd4da23f8/health-infra-cluster?${__all_variables}&${__url_time_range}" + }, + { + "targetBlank": true, + "title": "Open K8s / Compute Resources / Cluster", + "url": "/d/efa86fd1d0c121a26444b636a3f56738/kubernetes-compute-resources-cluster?${cluster:queryparam}&${__url_time_range}" + } + ], + "maxPerRow": 12, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.9, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "repeat": "cluster", + "repeatDirection": "h", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Node Health Status\r\n####################\r\n# RED (0) if no nodes ready without pressure\r\n# YELLOW (0.5) if at least one node not ready or with pressure\r\n# Green (1.0) otherwise\r\nlabel_replace(\r\n sum(\r\n max by (node) (kube_node_status_condition{cluster=~\"$cluster\",condition=\"ready\",status=\"false\"} > 0) * 0 or\r\n max by (node) (kube_node_status_condition{cluster=~\"$cluster\",condition!=\"ready\",status=\"true\"} > 0) * 0.5 or\r\n max by (node) (kube_node_status_condition{cluster=~\"$cluster\",condition=\"ready\",status=\"true\"} > 0) * 1\r\n ) / sum(kube_node_info{cluster=~\"$cluster\"})\r\n ,\"_\",\"Node Readiness\",\"\",\"\")\r\n#or label_replace(sum(kube_node_info),\"_\",\"Node Total Count\",\"\",\"\")\r\n#or label_replace(sum(kube_node_status_condition{condition=\"Ready\",status=\"true\"}),\"_\",\"Node Ready Count\",\"\",\"\")\r\n#or label_replace( sum(max by (node) (kube_node_status_condition{condition!=\"Ready\",status=\"true\"})),\"_\", \"Node Pressure Count\",\"\",\"\")\r\n#or label_replace(max by (node) (kube_node_status_condition{condition=\"Ready\",status=\"false\"}),\"_\",\"Node Ready Count\",\"\",\"\")\r\n#or label_replace(max by (node) (kube_node_status_condition{condition!=\"Ready\",status=\"true\"}),\"_\", \"Node Pressure Count\",\"\",\"\")\r\n#or label_replace(sum(sgn(\r\n# max by (node) (kube_node_status_condition{condition=\"Ready\",status=\"false\"})\r\n# + max by (node) (kube_node_status_condition{condition!=\"Ready\",status=\"true\"})\r\n# )),\"_\",\"Unhealthy Node Count\",\"\",\"\")", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#############################\r\n# Node CPU Health\r\nlabel_replace(min(\r\n# BEGIN inner query\r\nmin by(_)(label_replace(vector(0)>0\r\n or 0.0 * sgn(\r\n 100 - ((avg by (instance) (rate(node_cpu_seconds_total{cluster=~\"$cluster\",mode=\"idle\"}[5m])) \r\n + avg by (instance) (rate(node_cpu_seconds_total{cluster=~\"$cluster\",mode=\"iowait\"}[5m]))\r\n ) * 100) > $nodeThresholdRed)\r\n or 0.5 * sgn(\r\n 100 - ((avg by (instance) (rate(node_cpu_seconds_total{cluster=~\"$cluster\",mode=\"idle\"}[5m])) \r\n + avg by (instance) (rate(node_cpu_seconds_total{cluster=~\"$cluster\",mode=\"iowait\"}[5m]))\r\n ) * 100) > $nodeThresholdYellow)\r\n or 1.0 * sgn(sum by (instance)(node_cpu_seconds_total{cluster=~\"$cluster\"} > 0))\r\n or -1 * sgn(max by (instance) (label_replace(kube_node_info{cluster=~\"$cluster\"},\"instance\",\"$1\",\"node\",\"(.*)\")))\r\n ,\"_\",\"$1\",\"instance\",\"(.*)\"))\r\n# END inner query\r\n),\"_\",\"Node CPU\", \"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#############################\r\n# Node Memory Health\r\nlabel_replace(min(\r\n# BEGIN inner query\r\nmin by(_)(label_replace(vector(0)>0\r\n or 0.0 * sgn(\r\n (100 * sum by (instance)(node_memory_MemTotal_bytes{cluster=~\"$cluster\"} - (node_memory_MemFree_bytes{cluster=~\"$cluster\"} + node_memory_Buffers_bytes{cluster=~\"$cluster\"} + node_memory_Cached_bytes{cluster=~\"$cluster\"})) / sum by(instance) (node_memory_MemTotal_bytes{cluster=~\"$cluster\"})) > $nodeThresholdRed)\r\n or 0.5 * sgn(\r\n (100 * sum by (instance)(node_memory_MemTotal_bytes{cluster=~\"$cluster\"} - (node_memory_MemFree_bytes{cluster=~\"$cluster\"} + node_memory_Buffers_bytes{cluster=~\"$cluster\"} + node_memory_Cached_bytes{cluster=~\"$cluster\"})) / sum by(instance) (node_memory_MemTotal_bytes{cluster=~\"$cluster\"})) > $nodeThresholdYellow)\r\n or 1.0 * sgn(sum by (instance)(node_memory_MemTotal_bytes{cluster=~\"$cluster\"} > 0))\r\n or -1 * sgn(max by (instance) (label_replace(kube_node_info{cluster=~\"$cluster\"},\"instance\",\"$1\",\"node\",\"(.*)\")))\r\n,\"_\",\"$1\",\"instance\",\"(.*)\"))\r\n# END inner query\r\n),\"_\",\"Node Memory\", \"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#############################\r\n# Disk Usage Health\r\nlabel_replace(min(\r\n# BEGIN inner query\r\nmin by(node)(label_replace(vector(0)>0\r\n or 0.0 * sgn(max by(instance) (100 - (100 * node_filesystem_avail_bytes{cluster=~\"$cluster\"} \r\n / node_filesystem_size_bytes{cluster=~\"$cluster\"}) > 10) > $nodeThresholdRed)\r\n or 0.5 * sgn(max by(instance) (100 - (100 * node_filesystem_avail_bytes{cluster=~\"$cluster\"} \r\n / node_filesystem_size_bytes{cluster=~\"$cluster\"}) > 10) > $nodeThresholdYellow)\r\n or 1.0 * sgn(max by(instance) (100 - (100 * node_filesystem_avail_bytes{cluster=~\"$cluster\"} \r\n / node_filesystem_size_bytes{cluster=~\"$cluster\"})))\r\n,\"node\",\"$1\",\"instance\",\"(.*)\"))\r\nor max by (node) (kube_node_info{cluster=\"$cluster\"}) * -1 # Baseline by node\r\n# END inner query\r\n),\"_\",\"Node Disk\", \"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Kubernetes Node Health", + "transformations": [], + "transparent": true, + "type": "state-timeline" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 2, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_node_status_condition", + "description": "AIO cluster(s) to view", + "hide": 0, + "includeAll": true, + "label": "Cluster", + "multi": true, + "name": "cluster", + "options": [], + "query": { + "query": "kube_node_status_condition", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "/.*cluster=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "hide": 2, + "includeAll": true, + "multi": true, + "name": "namespace", + "options": [], + "query": { + "query": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "hide": 2, + "name": "aio_dp_self_test_pipeline", + "query": "${VAR_AIO_DP_SELF_TEST_PIPELINE}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_AIO_DP_SELF_TEST_PIPELINE}", + "text": "${VAR_AIO_DP_SELF_TEST_PIPELINE}", + "selected": false + }, + "options": [ + { + "value": "${VAR_AIO_DP_SELF_TEST_PIPELINE}", + "text": "${VAR_AIO_DP_SELF_TEST_PIPELINE}", + "selected": false + } + ] + }, + { + "hide": 2, + "name": "bf_latency_threshold_ms", + "query": "${VAR_BF_LATENCY_THRESHOLD_MS}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_BF_LATENCY_THRESHOLD_MS}", + "text": "${VAR_BF_LATENCY_THRESHOLD_MS}", + "selected": false + }, + "options": [ + { + "value": "${VAR_BF_LATENCY_THRESHOLD_MS}", + "text": "${VAR_BF_LATENCY_THRESHOLD_MS}", + "selected": false + } + ] + }, + { + "hide": 2, + "name": "aio_opc_latency_threshold_ms", + "query": "${VAR_AIO_OPC_LATENCY_THRESHOLD_MS}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_AIO_OPC_LATENCY_THRESHOLD_MS}", + "text": "${VAR_AIO_OPC_LATENCY_THRESHOLD_MS}", + "selected": false + }, + "options": [ + { + "value": "${VAR_AIO_OPC_LATENCY_THRESHOLD_MS}", + "text": "${VAR_AIO_OPC_LATENCY_THRESHOLD_MS}", + "selected": false + } + ] + }, + { + "description": "Threshold in percent (1-100) for determining red/error health state for node-level resources", + "hide": 2, + "name": "nodeThresholdRed", + "query": "${VAR_NODETHRESHOLDRED}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_NODETHRESHOLDRED}", + "text": "${VAR_NODETHRESHOLDRED}", + "selected": false + }, + "options": [ + { + "value": "${VAR_NODETHRESHOLDRED}", + "text": "${VAR_NODETHRESHOLDRED}", + "selected": false + } + ] + }, + { + "description": "Threshold in percent (1-100) for determining yellow/warning health state for node-level resources", + "hide": 2, + "name": "nodeThresholdYellow", + "query": "${VAR_NODETHRESHOLDYELLOW}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_NODETHRESHOLDYELLOW}", + "text": "${VAR_NODETHRESHOLDYELLOW}", + "selected": false + }, + "options": [ + { + "value": "${VAR_NODETHRESHOLDYELLOW}", + "text": "${VAR_NODETHRESHOLDYELLOW}", + "selected": false + } + ] + }, + { + "description": "Success Rate goal for SLOs; below this value is considered missed SLO", + "hide": 2, + "name": "opc_slo_sr_goal", + "query": "${VAR_OPC_SLO_SR_GOAL}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_OPC_SLO_SR_GOAL}", + "text": "${VAR_OPC_SLO_SR_GOAL}", + "selected": false + }, + "options": [ + { + "value": "${VAR_OPC_SLO_SR_GOAL}", + "text": "${VAR_OPC_SLO_SR_GOAL}", + "selected": false + } + ] + }, + { + "description": "Latency goal for SLOs (in milliseconds); above this value is considered missed SLO", + "hide": 2, + "name": "opc_slo_publish_latency_ms_goal", + "query": "${VAR_OPC_SLO_PUBLISH_LATENCY_MS_GOAL}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_OPC_SLO_PUBLISH_LATENCY_MS_GOAL}", + "text": "${VAR_OPC_SLO_PUBLISH_LATENCY_MS_GOAL}", + "selected": false + }, + "options": [ + { + "value": "${VAR_OPC_SLO_PUBLISH_LATENCY_MS_GOAL}", + "text": "${VAR_OPC_SLO_PUBLISH_LATENCY_MS_GOAL}", + "selected": false + } + ] + }, + { + "description": "Latency goal for SLOs (in milliseconds); above this value is considered missed SLO", + "hide": 2, + "name": "opc_slo_connect_latency_ms_goal", + "query": "${VAR_OPC_SLO_CONNECT_LATENCY_MS_GOAL}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_OPC_SLO_CONNECT_LATENCY_MS_GOAL}", + "text": "${VAR_OPC_SLO_CONNECT_LATENCY_MS_GOAL}", + "selected": false + }, + "options": [ + { + "value": "${VAR_OPC_SLO_CONNECT_LATENCY_MS_GOAL}", + "text": "${VAR_OPC_SLO_CONNECT_LATENCY_MS_GOAL}", + "selected": false + } + ] + }, + { + "description": "Latency threshold for health signal", + "hide": 2, + "name": "orc_latency_threshold_ms", + "query": "${VAR_ORC_LATENCY_THRESHOLD_MS}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_ORC_LATENCY_THRESHOLD_MS}", + "text": "${VAR_ORC_LATENCY_THRESHOLD_MS}", + "selected": false + }, + "options": [ + { + "value": "${VAR_ORC_LATENCY_THRESHOLD_MS}", + "text": "${VAR_ORC_LATENCY_THRESHOLD_MS}", + "selected": false + } + ] + }, + { + "hide": 2, + "name": "aio_dp_error_threshold", + "query": "${VAR_AIO_DP_ERROR_THRESHOLD}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_AIO_DP_ERROR_THRESHOLD}", + "text": "${VAR_AIO_DP_ERROR_THRESHOLD}", + "selected": false + }, + "options": [ + { + "value": "${VAR_AIO_DP_ERROR_THRESHOLD}", + "text": "${VAR_AIO_DP_ERROR_THRESHOLD}", + "selected": false + } + ] + }, + { + "description": "", + "hide": 2, + "name": "aio_dp_nats_utilization_threshold", + "query": "${VAR_AIO_DP_NATS_UTILIZATION_THRESHOLD}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_AIO_DP_NATS_UTILIZATION_THRESHOLD}", + "text": "${VAR_AIO_DP_NATS_UTILIZATION_THRESHOLD}", + "selected": false + }, + "options": [ + { + "value": "${VAR_AIO_DP_NATS_UTILIZATION_THRESHOLD}", + "text": "${VAR_AIO_DP_NATS_UTILIZATION_THRESHOLD}", + "selected": false + } + ] + }, + { + "hide": 2, + "name": "aio_dp_error_rate", + "query": "${VAR_AIO_DP_ERROR_RATE}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_AIO_DP_ERROR_RATE}", + "text": "${VAR_AIO_DP_ERROR_RATE}", + "selected": false + }, + "options": [ + { + "value": "${VAR_AIO_DP_ERROR_RATE}", + "text": "${VAR_AIO_DP_ERROR_RATE}", + "selected": false + } + ] + }, + { + "hide": 2, + "name": "aio_dp_latency_threshold_ms", + "query": "${VAR_AIO_DP_LATENCY_THRESHOLD_MS}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_AIO_DP_LATENCY_THRESHOLD_MS}", + "text": "${VAR_AIO_DP_LATENCY_THRESHOLD_MS}", + "selected": false + }, + "options": [ + { + "value": "${VAR_AIO_DP_LATENCY_THRESHOLD_MS}", + "text": "${VAR_AIO_DP_LATENCY_THRESHOLD_MS}", + "selected": false + } + ] + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "aio-health", + "uid": "c4c37068-3940-40ba-8c20-67b3ce4923e9", + "version": 17, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-health-infra-cluster-1698853541941.json b/samples/dashboard/grafana-dashboards/aio-health-infra-cluster-1698853541941.json new file mode 100644 index 0000000..d883bf5 --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-health-infra-cluster-1698853541941.json @@ -0,0 +1,1353 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + }, + { + "name": "VAR_NODETHRESHOLDRED", + "type": "constant", + "label": "nodeThresholdRed", + "value": "90", + "description": "" + }, + { + "name": "VAR_NODETHRESHOLDYELLOW", + "type": "constant", + "label": "nodeThresholdYellow", + "value": "80", + "description": "" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "state-timeline", + "name": "State timeline", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [ + { + "asDropdown": false, + "icon": "dashboard", + "includeVars": true, + "keepTime": true, + "tags": [], + "targetBlank": true, + "title": "Managed Prometheus - AKS Node Report", + "tooltip": "", + "type": "link", + "url": "/d/D4pVs6738/node-exporter-nodes" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 5, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n Azure Edge Services - Infrastructure Cluster Health\n
\n
\n   Node Health\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 15, + "x": 0, + "y": 3 + }, + "id": 1, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.9, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Node Health Status\r\n####################\r\n# RED (0) if no nodes ready without pressure\r\n# YELLOW (0.5) if at least one node not ready or with pressure\r\n# Green (1.0) otherwise\r\n#label_replace(\r\nmax by (node) (kube_node_status_condition{cluster=~\"$cluster\",condition=\"ready\",status=\"false\"} > 0) * 0 or\r\nmax by (node) (kube_node_status_condition{cluster=~\"$cluster\",condition!=\"ready\",status=\"true\"} > 0) * 0.5 or\r\nmax by (node) (kube_node_status_condition{cluster=~\"$cluster\",condition=\"ready\",status=\"true\"} > 0) * 1\r\n#) / sum(kube_node_info)# ,\"_\",\"Node Health\",\"\",\"\")\r\n#or label_replace(sum(kube_node_info),\"_\",\"Node Total Count\",\"\",\"\")\r\n#or label_replace(sum(kube_node_status_condition{condition=\"Ready\",status=\"true\"}),\"_\",\"Node Ready Count\",\"\",\"\")\r\n#or label_replace( sum(max by (node) (kube_node_status_condition{condition!=\"Ready\",status=\"true\"})),\"_\", \"Node Pressure Count\",\"\",\"\")\r\n#or label_replace(max by (node) (kube_node_status_condition{condition=\"Ready\",status=\"false\"}),\"_\",\"Node Ready Count\",\"\",\"\")\r\n#or label_replace(max by (node) (kube_node_status_condition{condition!=\"Ready\",status=\"true\"}),\"_\", \"Node Pressure Count\",\"\",\"\")\r\n#or label_replace(sum(sgn(\r\n# max by (node) (kube_node_status_condition{condition=\"Ready\",status=\"false\"})\r\n# + max by (node) (kube_node_status_condition{condition!=\"Ready\",status=\"true\"})\r\n# )),\"_\",\"Unhealthy Node Count\",\"\",\"\")", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Node Ready Health", + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMax": 2, + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "_" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "transparent", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "# Ready" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "line" + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 9, + "x": 15, + "y": 3 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Node Health Details\r\n####################\r\nlabel_replace(sum (kube_node_status_condition{cluster=~\"$cluster\",condition=\"Ready\",status=\"true\"}),\"_\",\"# Ready\",\"\",\"\") or\r\nmax by(_)(label_replace(label_join(\r\n label_replace(max by (node,condition) (kube_node_status_condition{cluster=~\"$cluster\",condition=\"Ready\",status=\"false\"}), \"condition\",\"Not Ready\",\"\",\"\") > 0\r\n or max by (node,condition) (kube_node_status_condition{cluster=~\"$cluster\",condition!=\"Ready\",status=\"true\"}) > 0\r\n ,\"_\",\":\",\"condition\",\"node\")\r\n ,\"_\",\"$1($2)\",\"_\",\"([^:]*):(.*)\")\r\n) \r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# X-axis normalizer\r\nmin(kube_node_status_condition{cluster=~\"$cluster\",condition=\"Ready\"})", + "hide": true, + "interval": "15m", + "legendFormat": "_", + "range": true, + "refId": "B" + } + ], + "title": "Node Ready Health Issue Details", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "AKS Reports - K8s / Node Exporter / Nodes", + "url": "/d/D4pVs6738/node-exporter-nodes?${__url_time_range}&${cluster:queryparam}&var-instance=${__field.labels._}" + }, + { + "targetBlank": true, + "title": "AKS Reports - K8s / Node Exporter / USE Method / Node", + "url": "/d/t5aja6738/node-exporter-use-method-node?${__url_time_range}&${cluster:queryparam}&var-instance=${__field.labels._}" + }, + { + "targetBlank": true, + "title": "AKS Reports - K8s / Compute Resources / Node (Pods)", + "url": "/d/200ac8fdbfbb74b39aff88118e4d6738/kubernetes-compute-resources-node-pods?${__url_time_range}&${cluster:queryparam}&var-node=${__field.labels._}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#808080", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 15, + "x": 0, + "y": 8 + }, + "id": 8, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.9, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#############################\r\n# Node CPU Health\r\nmin by(_)(label_replace(vector(0)>0\r\n or 0.0 * sgn(\r\n 100 - ((avg by (instance) (rate(node_cpu_seconds_total{cluster=~\"$cluster\",mode=\"idle\"}[5m])) \r\n + avg by (instance) (rate(node_cpu_seconds_total{cluster=~\"$cluster\",mode=\"iowait\"}[5m]))\r\n ) * 100) > $nodeThresholdRed)\r\n or 0.5 * sgn(\r\n 100 - ((avg by (instance) (rate(node_cpu_seconds_total{cluster=~\"$cluster\",mode=\"idle\"}[5m])) \r\n + avg by (instance) (rate(node_cpu_seconds_total{cluster=~\"$cluster\",mode=\"iowait\"}[5m]))\r\n ) * 100) > $nodeThresholdYellow)\r\n or 1.0 * sgn(sum by (instance)(node_cpu_seconds_total{cluster=~\"$cluster\"} > 0))\r\n or -1 * sgn(max by (instance) (label_replace(kube_node_info{cluster=~\"$cluster\"},\"instance\",\"$1\",\"node\",\"(.*)\")))\r\n ,\"_\",\"$1\",\"instance\",\"(.*)\"))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#############################\r\n# Node CPU Health\r\nmax by (node) (kube_node_info{cluster=\"$cluster\"}) * 0 and\r\nmax by (node) (label_replace(\r\n 100 - ((avg by (instance) (rate(node_cpu_seconds_total{cluster=\"$cluster\",mode=\"idle\"}[5m])) \r\n + avg by (instance) (rate(node_cpu_seconds_total{cluster=\"$cluster\",mode=\"iowait\"}[5m]))\r\n ) * 100)\r\n #* on (instance) group_left(node) label_replace(max by(internal_ip,node) (kube_node_info),\"instance\",\"$1:9100\",\"internal_ip\",\"(.*)\") # Node Info\r\n ,\"node\",\"$1\",\"instance\",\"(.*)\")\r\n> 50 # THRESHOLD VALUE FOR RED\r\n# Show -1 if node_cpu_seconds_total metric is missing for the node\r\n) or sgn(max by (node) (kube_node_info{cluster=\"$cluster\"})) * -1 unless \r\n count by(node)(label_replace(node_cpu_seconds_total{cluster=\"$cluster\"},\"node\",\"$1\",\"instance\",\"(.*)\"))\r\nor max by (node) (kube_node_info{cluster=\"$cluster\"}) # Baseline by node", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Node CPU Health", + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMax": 100, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "_" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "transparent", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unhealthy" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + }, + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Warning" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + }, + { + "id": "color", + "value": { + "fixedColor": "dark-yellow", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 9, + "x": 15, + "y": 8 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#############################\r\n# Node CPU Usage Pecent\r\nmax by (_) (label_replace(\r\n 100 - ((avg by (instance) (rate(node_cpu_seconds_total{cluster=\"$cluster\",mode=\"idle\"}[5m])) \r\n + avg by (instance) (rate(node_cpu_seconds_total{cluster=\"$cluster\",mode=\"iowait\"}[5m]))\r\n ) * 100)\r\n #* on (instance) group_left(node) label_replace(max by(internal_ip,node) (kube_node_info),\"instance\",\"$1:9100\",\"internal_ip\",\"(.*)\") # Node Info\r\n ,\"_\",\"$1\",\"instance\",\"(.*)\")\r\n)\r\nor label_replace(vector($nodeThresholdRed),\"_\",\"Unhealthy\",\"\",\"\")\r\nor label_replace(vector($nodeThresholdYellow),\"_\",\"Warning\",\"\",\"\")", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Node CPU Utilization", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "AKS Reports - K8s / Node Exporter / Nodes", + "url": "/d/D4pVs6738/node-exporter-nodes?${__url_time_range}&${cluster:queryparam}&var-instance=${__field.labels._}" + }, + { + "targetBlank": true, + "title": "AKS Reports - K8s / Node Exporter / USE Method / Node", + "url": "/d/t5aja6738/node-exporter-use-method-node?${__url_time_range}&${cluster:queryparam}&var-instance=${__field.labels._}" + }, + { + "targetBlank": true, + "title": "AKS Reports - K8s / Compute Resources / Node (Pods)", + "url": "/d/200ac8fdbfbb74b39aff88118e4d6738/kubernetes-compute-resources-node-pods?${__url_time_range}&${cluster:queryparam}&var-node=${__field.labels._}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#808080", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 15, + "x": 0, + "y": 13 + }, + "id": 10, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.9, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#############################\r\n# Node Memory Health\r\nmin by(_)(label_replace(vector(0)>0\r\n or 0.0 * sgn(\r\n (100 * sum by (instance)(node_memory_MemTotal_bytes{cluster=~\"$cluster\"} - (node_memory_MemFree_bytes{cluster=~\"$cluster\"} + node_memory_Buffers_bytes{cluster=~\"$cluster\"} + node_memory_Cached_bytes{cluster=~\"$cluster\"})) / sum by(instance) (node_memory_MemTotal_bytes{cluster=~\"$cluster\"})) > $nodeThresholdRed)\r\n or 0.5 * sgn(\r\n (100 * sum by (instance)(node_memory_MemTotal_bytes{cluster=~\"$cluster\"} - (node_memory_MemFree_bytes{cluster=~\"$cluster\"} + node_memory_Buffers_bytes{cluster=~\"$cluster\"} + node_memory_Cached_bytes{cluster=~\"$cluster\"})) / sum by(instance) (node_memory_MemTotal_bytes{cluster=~\"$cluster\"})) > $nodeThresholdYellow)\r\n or 1.0 * sgn(sum by (instance)(node_memory_MemTotal_bytes{cluster=~\"$cluster\"} > 0))\r\n or -1 * sgn(max by (instance) (label_replace(kube_node_info{cluster=~\"$cluster\"},\"instance\",\"$1\",\"node\",\"(.*)\")))\r\n,\"_\",\"$1\",\"instance\",\"(.*)\"))\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#############################\r\n# Node Memory Health\r\nmax by (node) (kube_node_info{cluster=\"$cluster\"}) * 0 and (\r\n min by (node) (label_replace(\r\n (100 * sum by (instance)\r\n (node_memory_MemTotal_bytes{cluster=\"$cluster\"} \r\n - node_memory_MemFree_bytes{cluster=\"$cluster\"} \r\n - node_memory_Buffers_bytes{cluster=\"$cluster\"} \r\n - node_memory_Cached_bytes{cluster=\"$cluster\"}) \r\n / sum by(instance) (node_memory_MemTotal_bytes{cluster=\"$cluster\"}))\r\n #* on (instance) group_left(node) label_replace(\r\n # max by(internal_ip,node) (kube_node_info),\"instance\",\"$1:9100\",\"internal_ip\",\"(.*)\") # Node Info\r\n ,\"node\",\"$1\",\"instance\",\"(.*)\")\r\n )\r\n> 50 # THRESHOLD VALUE FOR RED\r\n) or sgn(max by (node) (kube_node_info{cluster=\"$cluster\"})) * -1 unless \r\n count by(node)(label_replace(node_memory_MemTotal_bytes{cluster=\"$cluster\"},\"node\",\"$1\",\"instance\",\"(.*)\"))\r\nor max by (node) (kube_node_info{cluster=\"$cluster\"}) # Baseline by node\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Node Memory Health", + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMax": 100, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "_" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "transparent", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unhealthy" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + }, + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Warning" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "dark-yellow", + "mode": "fixed" + } + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 9, + "x": 15, + "y": 13 + }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#############################\r\n# Node Memory Usage Pecent\r\nmin by (_) (label_replace(\r\n (100 * sum by (instance)\r\n (node_memory_MemTotal_bytes{cluster=\"$cluster\"} \r\n - node_memory_MemFree_bytes{cluster=\"$cluster\"} \r\n - node_memory_Buffers_bytes{cluster=\"$cluster\"} \r\n - node_memory_Cached_bytes{cluster=\"$cluster\"}) \r\n / sum by(instance) (node_memory_MemTotal_bytes{cluster=\"$cluster\"}))\r\n ,\"_\",\"$1\",\"instance\",\"(.*)\")\r\n)\r\nor label_replace(vector($nodeThresholdRed),\"_\",\"Unhealthy\",\"\",\"\")\r\nor label_replace(vector($nodeThresholdYellow),\"_\",\"Warning\",\"\",\"\")", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Node Memory Utilization", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "AKS Reports - K8s / Node Exporter / Nodes", + "url": "/d/D4pVs6738/node-exporter-nodes?${__url_time_range}&${cluster:queryparam}&var-instance=${__field.labels.node}" + }, + { + "targetBlank": true, + "title": "AKS Reports - K8s / Node Exporter / USE Method / Node", + "url": "/d/t5aja6738/node-exporter-use-method-node?${__url_time_range}&${cluster:queryparam}&var-instance=${__field.labels.node}" + }, + { + "targetBlank": true, + "title": "AKS Reports - K8s / Compute Resources / Node (Pods)", + "url": "/d/200ac8fdbfbb74b39aff88118e4d6738/kubernetes-compute-resources-node-pods?${__url_time_range}&${cluster:queryparam}&var-node=${__field.labels.node}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#808080", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 15, + "x": 0, + "y": 18 + }, + "id": 12, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.9, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#############################\r\n# Disk Usage Health\r\nmin by(node)(label_replace(vector(0)>0\r\n or 0.0 * sgn(max by(instance) (100 - (100 * node_filesystem_avail_bytes{cluster=~\"$cluster\"} \r\n / node_filesystem_size_bytes{cluster=~\"$cluster\"}) > 10) > $nodeThresholdRed)\r\n or 0.5 * sgn(max by(instance) (100 - (100 * node_filesystem_avail_bytes{cluster=~\"$cluster\"} \r\n / node_filesystem_size_bytes{cluster=~\"$cluster\"}) > 10) > $nodeThresholdYellow)\r\n or 1.0 * sgn(max by(instance) (100 - (100 * node_filesystem_avail_bytes{cluster=~\"$cluster\"} \r\n / node_filesystem_size_bytes{cluster=~\"$cluster\"})))\r\n,\"node\",\"$1\",\"instance\",\"(.*)\"))\r\nor max by (node) (kube_node_info{cluster=\"$cluster\"}) * -1 # Baseline by node", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#############################\r\n# Disk Usage Health\r\nmax by (node) (kube_node_info{cluster=\"$cluster\"}) * 0 and (\r\n max by (node) (label_replace( #,device) (\r\n min by(instance,device) (100 - (100 * node_filesystem_avail_bytes{cluster=\"$cluster\"} / node_filesystem_size_bytes{cluster=\"$cluster\"}) > 5)\r\n # * on (instance) group_left(node) label_replace(max by(internal_ip,node) (kube_node_info),\"instance\",\"$1:9100\",\"internal_ip\",\"(.*)\") # Node Info\r\n ,\"node\",\"$1\",\"instance\",\"(.*)\")\r\n )\r\n# or label_replace(vector(60),\"threshold\",\"redline\",\"\",\"\")\r\n> 60 # THRESHOLD VALUE FOR RED\r\n) or sgn(max by (node) (kube_node_info{cluster=\"$cluster\"})) * -1 unless \r\n count by(node)(label_replace(node_filesystem_avail_bytes{cluster=\"$cluster\"},\"node\",\"$1\",\"instance\",\"(.*)\"))\r\nor max by (node) (kube_node_info{cluster=\"$cluster\"}) # Baseline by node", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Node Disk Health", + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMax": 100, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "_" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "transparent", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unhealthy" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Warning" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "dark-yellow", + "mode": "fixed" + } + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 9, + "x": 15, + "y": 18 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#############################\r\n# Disk Usage\r\nmax by(_) (label_replace(label_join(\r\n max by (node,device) (label_replace(\r\n min by(instance,device) (100 - (100 * node_filesystem_avail_bytes{cluster=\"$cluster\"} / node_filesystem_size_bytes{cluster=\"$cluster\"}) > 10)\r\n ,\"node\",\"$1\",\"instance\",\"(.*)\")\r\n ),\"nodeDevice\",\",\",\"node\",\"device\")\r\n ,\"_\",\"$1($2)\",\"nodeDevice\",\"^([^,]+)[,](.*)$\")\r\n)\r\nor label_replace(vector($nodeThresholdRed),\"_\",\"Unhealthy\",\"\",\"\")\r\nor label_replace(vector($nodeThresholdYellow),\"_\",\"Warning\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Node Disk Utilization", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 13, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# How to use this dashboard\nThis dashboard highlights cluster-level health signals that may\naffect Azure Edge Services health and is broken down into the\nfollowing sections:\n\n#### Node health\nThis section breaks down Node health starting with Node \nReadiness/pressure signals to health by resource. The left side\nshows basic health signal where YELLOW and RED indicate when a node\nhas crossed corresponding thresholds. The right side provides a \nmore detailed view behind the health signal shown on the left.\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "type": "text" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_node_status_condition", + "description": "PAS Cluster to view", + "hide": 0, + "includeAll": false, + "label": "Cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "kube_node_status_condition", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*cluster=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "description": "Used by other dashboards, but not used here except perhaps for drilldowns to other dashboards.", + "hide": 2, + "includeAll": false, + "multi": true, + "name": "namespace", + "options": [], + "query": { + "query": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "description": "Threshold in percent (1-100) for determining red/error health state for node-level resources", + "hide": 2, + "name": "nodeThresholdRed", + "query": "${VAR_NODETHRESHOLDRED}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_NODETHRESHOLDRED}", + "text": "${VAR_NODETHRESHOLDRED}", + "selected": false + }, + "options": [ + { + "value": "${VAR_NODETHRESHOLDRED}", + "text": "${VAR_NODETHRESHOLDRED}", + "selected": false + } + ] + }, + { + "description": "Threshold in percent (1-100) for determining yellow/warning health state for node-level resources", + "hide": 2, + "name": "nodeThresholdYellow", + "query": "${VAR_NODETHRESHOLDYELLOW}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_NODETHRESHOLDYELLOW}", + "text": "${VAR_NODETHRESHOLDYELLOW}", + "selected": false + }, + "options": [ + { + "value": "${VAR_NODETHRESHOLDYELLOW}", + "text": "${VAR_NODETHRESHOLDYELLOW}", + "selected": false + } + ] + } + ] + }, + "time": { + "from": "now-7d", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "aio-health-infra-cluster", + "uid": "e159191f-81f2-4443-af47-fe7cd4da23f8", + "version": 31, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-health-infra-pod-1698853566878.json b/samples/dashboard/grafana-dashboards/aio-health-infra-pod-1698853566878.json new file mode 100644 index 0000000..9cfbb36 --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-health-infra-pod-1698853566878.json @@ -0,0 +1,2099 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + }, + { + "name": "DS_AZURE_MONITOR", + "label": "Azure Monitor", + "description": "", + "type": "datasource", + "pluginId": "grafana-azure-monitor-datasource", + "pluginName": "Azure Monitor" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "grafana-azure-monitor-datasource", + "name": "Azure Monitor", + "version": "1.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "state-timeline", + "name": "State timeline", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 8, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n Azure Edge Services - Pod Health\n
\n
\n   Pod Health - $pod\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "Click for more details", + "url": "/d/eef9bf1c-b27a-4e86-a7f0-2a39cdfbeeca/health-infrastructure?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#808080", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 0, + "y": 3 + }, + "id": 31, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.9, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Workload Readiness health\r\n############################\r\nlabel_replace(min(\r\n kube_pod_status_phase{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\",phase=~\"running|succeeded\"} > 0 or\r\n kube_pod_status_phase{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\",phase!~\"running|succeeded\"} > 0 * 0 or\r\n vector(0)>0\r\n) or vector(-1),\"_\",\"Pod Readiness\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Restart Health:\r\n############################\r\nlabel_replace(\r\n sgn(sum_over_time(sum(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"${component:raw}\",pod=~\"$pod\"}[10m:1m]\r\n )*60)[1h:]) > 5) * 0.0 # RED: Cumulative restarts over X(5) time greater than Y(1h)\r\n or (max(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"${component:raw}\",pod=~\"$pod\"}[5m:1m]\r\n )*60*5) > 0) * 0.5 # YELLOW: restarts detected but below Red threshold\r\n or sgn(max(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"${component:raw}\",pod=~\"$pod\"}\r\n + 1 >= 0))\r\n #or vector(1) # Healthy\r\n ,\"_\",\"Container Restart Health\",\"\",\"\")\r\n## uncomment below to t-shoot this health metric\r\n# or label_replace(sum_over_time(sum(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[10m:1m])*60)[1h:]),\"_\",\"Total-restarts-over-time\",\"\",\"\")\r\n# or label_replace((max(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[5m:1m])*60*5) without (__name__,uid,instance,job) > 0),\"_\",\"restart\",\"\",\"\") # Base query for counting restarts\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container CPU top-level health\r\n################################\r\nlabel_replace(\r\nmin(sgn( # Check for throttling > N indicating container is exceeding its CPU limits\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\",pod=~\"$pod\"}[10m]) \r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\",pod=~\"$pod\"}[10m])\r\n > 0.20) # If throttle create is greater than this percentage, we'll multiply sgn by 0.5 to show as error (or warning depending on threshold coloring)\r\n ) # by (namespace,container) # These are commented out for top-level\r\n * 0.5\r\nor\r\nmin( # Check to see if container is missing CPU Limits configuration\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"cpu\",pod=~\"${component:raw}\",pod=~\"$pod\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\",pod=~\"$pod\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n ) #by (namespace,container) # These are commented out for top-level\r\n,\"_\",\"Container CPU Health\",\"\",\"\")", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Memory Health:\r\n###########################\r\nlabel_replace(\r\nmin( # Look for high memory utilization\r\n sgn((\r\n max(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\",pod=~\"$pod\"}) by (namespace,container)\r\n / min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"memory\",pod=~\"${component:raw}\",pod=~\"$pod\"}) by (namespace, container)\r\n ) >= .95) - 0.5 # show health state of 0.5 if container memory utilization >= 95%\r\n) #by (container) \r\nor\r\nmin( # Look for missing limits which we will show as 0 if missing\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"memory\",pod=~\"${component:raw}\",pod=~\"$pod\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\",pod=~\"$pod\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n) #by (container) \r\n,\"_\",\"Container Memory health\",\"\",\"\")", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Health Summary", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "max(rate(container_cpu_usage_seconds_total{namespace=~\"alice-springs|symphony-k8s-system\",container=\"\",cpu=\"total\"}[5m])*300 > 0) ": "POD CPU (max)", + "min( # Workload ready percents (for deployment, daemonset, replicaset, and statefulset)\r\n label_replace(label_join(\r\n {job=\"kube-state-metrics\",namespace=~\"alice-springs|symphony-k8s-system\",\r\n __name__=~\"kube_(deployment|daemonset|replicaset|statefulset)_status_(replicas_ready|ready_replicas|number_ready)\"}\r\n ,\"workload\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n / label_replace(label_join(\r\n {job=\"kube-state-metrics\",namespace=~\"alice-springs|symphony-k8s-system\",\r\n __name__=~\"kube_(deployment|daemonset|replicaset|statefulset)_status_(replicas|desired_number_scheduled)\"}\r\n ,\"workload\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n) #by (workloadType) #namespace) #, workloadType) #, workload)": "Workload ready health" + } + } + } + ], + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "_" + }, + "properties": [ + { + "id": "custom.width", + "value": 70 + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "basic", + "type": "color-background" + } + }, + { + "id": "color", + "value": { + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "." + }, + "properties": [ + { + "id": "mappings", + "value": [ + { + "options": { + "failed": { + "color": "red", + "index": 0 + }, + "pending": { + "color": "yellow", + "index": 3 + }, + "running": { + "color": "green", + "index": 1 + }, + "succeeded": { + "color": "blue", + "index": 2 + }, + "unknown": { + "color": "orange", + "index": 4 + } + }, + "type": "value" + }, + { + "options": { + "pattern": ".*", + "result": { + "color": "text", + "index": 5 + } + }, + "type": "regex" + } + ] + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 3 + }, + "id": 60, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": false + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by(_,value)(\r\n#label_replace(label_replace(\r\n# (vector(1)\r\n# ),\"value\",\"$pod\",\"\",\"\"),\"_\",\"Pod:\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n (\r\n sum by(pod)(kube_pod_owner{cluster=~\"$cluster\",pod=~\"$pod\"})\r\n ),\"value\",\"$1\",\"pod\",\"(.*)\"),\"_\",\"Pod:\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n sum by(namespace)(kube_pod_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"}\r\n ),\"value\",\"$1\",\"namespace\",\"(.*)\"),\"_\",\"Namespace:\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n sum by(owner_kind,owner_name)( # Pod owner kind and name\r\n sum by(replicaset)(label_replace(\r\n sum by(owner_kind, owner_name)(\r\n kube_pod_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",owner_kind=\"replicaset\",pod=~\"$component\",pod=~\"$pod\"}\r\n ),\"replicaset\",\"$1\",\"owner_name\",\"(.*)\"))\r\n / on (replicaset) group_left(owner_kind, owner_name) \r\n sum by(owner_kind,owner_name,replicaset)(kube_replicaset_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",replicaset=~\"$component\"})\r\n or sum by(owner_kind, owner_name)(\r\n kube_pod_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",owner_kind!=\"replicaset\",pod=~\"$component\",pod=~\"$pod\"}\r\n )\r\n ),\"value\",\"$1\",\"owner_kind\",\"(.*)\"),\"_\",\"Type:\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n sum by(owner_kind,owner_name)( # Pod owner kind and name\r\n sum by(replicaset)(label_replace(\r\n sum by(owner_kind, owner_name)(\r\n kube_pod_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",owner_kind=\"replicaset\",pod=~\"$component\",pod=~\"$pod\"}\r\n ),\"replicaset\",\"$1\",\"owner_name\",\"(.*)\"))\r\n / on (replicaset) group_left(owner_kind, owner_name) \r\n sum by(owner_kind,owner_name,replicaset)(kube_replicaset_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",replicaset=~\"$component\"})\r\n or sum by(owner_kind, owner_name)(\r\n kube_pod_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",owner_kind!=\"replicaset\",pod=~\"$component\",pod=~\"$pod\"}\r\n )\r\n ),\"value\",\"$1\",\"owner_name\",\"(.*)\"),\"_\",\"Parent:\",\"\",\"\") or\r\n#label_replace(label_replace(\r\n# sum by(phase)(kube_pod_status_phase{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"} > 0\r\n# ),\"value\",\"$1\",\"phase\",\"(.*)\"),\"_\",\"State:\",\"\",\"\") or\r\nvector(0)>0)", + "format": "table", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": " Pod Summary", + "transformations": [ + { + "id": "convertFieldType", + "options": { + "conversions": [ + { + "destinationType": "boolean", + "targetField": "Time" + } + ], + "fields": {} + } + }, + { + "id": "groupingToMatrix", + "options": { + "columnField": "Time", + "rowField": "_", + "valueField": "value" + } + }, + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "_\\Time": "_", + "true": "." + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 1 + }, + { + "color": "red", + "value": 10 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "container" + }, + "properties": [ + { + "id": "custom.width", + "value": 150 + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "basic", + "type": "color-background" + } + }, + { + "id": "color", + "value": { + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Restarts" + }, + "properties": [ + { + "id": "custom.width", + "value": 75 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color" + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 3 + }, + "id": 76, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by(container)(kube_pod_container_info{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"}) \r\n/ on (container) group_right sum by(container,image)(\r\n kube_pod_container_info{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"})\r\n* on (container) group_left #label_replace(\r\n max by(container)(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"})\r\n", + "format": "table", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Container Summary", + "transformations": [ + { + "disabled": true, + "id": "convertFieldType", + "options": {} + }, + { + "id": "groupBy", + "options": { + "fields": { + "Time": { + "aggregations": [ + "lastNotNull" + ], + "operation": "aggregate" + }, + "Value": { + "aggregations": [ + "lastNotNull" + ], + "operation": "aggregate" + }, + "container": { + "aggregations": [], + "operation": "groupby" + }, + "image": { + "aggregations": [ + "lastNotNull" + ], + "operation": "aggregate" + } + } + } + }, + { + "disabled": true, + "id": "convertFieldType", + "options": { + "conversions": [ + { + "destinationType": "boolean", + "targetField": "Time" + } + ], + "fields": {} + } + }, + { + "id": "sortBy", + "options": { + "fields": {}, + "sort": [ + { + "field": "container" + } + ] + } + }, + { + "disabled": true, + "id": "organize", + "options": { + "excludeByName": { + "Time": true + }, + "indexByName": {}, + "renameByName": { + "Value": "Restarts", + "image": "" + } + } + }, + { + "id": "organize", + "options": { + "excludeByName": { + "Time (lastNotNull)": true + }, + "indexByName": {}, + "renameByName": { + "Value (lastNotNull)": "Restarts", + "image (lastNotNull)": "image" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "center", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "_" + }, + "properties": [ + { + "id": "custom.width", + "value": 55 + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "basic", + "type": "color-background" + } + }, + { + "id": "color", + "value": { + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "." + }, + "properties": [ + { + "id": "mappings", + "value": [ + { + "options": { + "failed": { + "color": "red", + "index": 0 + }, + "pending": { + "color": "yellow", + "index": 3 + }, + "running": { + "color": "green", + "index": 1 + }, + "succeeded": { + "color": "blue", + "index": 2 + }, + "unknown": { + "color": "orange", + "index": 4 + } + }, + "type": "value" + }, + { + "options": { + "pattern": ".*", + "result": { + "color": "text", + "index": 5 + } + }, + "type": "regex" + } + ] + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "custom.width", + "value": 120 + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 0, + "y": 6 + }, + "id": 63, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "frameIndex": 0, + "showHeader": false + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by(_,value)(\r\n#label_replace(label_replace(\r\n# (vector(1)\r\n# ),\"value\",\"$pod\",\"\",\"\"),\"_\",\"Pod:\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n sum by(phase)(kube_pod_status_phase{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"}) > 0 or\r\n label_replace(absent(present_over_time(sum(kube_pod_status_phase{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"})[$__rate_interval:])),\"phase\",\"deleted\",\"\",\"\"\r\n ),\"value\",\"$1\",\"phase\",\"(.*)\"),\"_\",\"State:\",\"\",\"\") or\r\n vector(0)>0)", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by(_,value)(\r\n#label_replace(label_replace(\r\n# (vector(1)\r\n# ),\"value\",\"$pod\",\"\",\"\"),\"_\",\"Pod:\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n (\r\n sum by(pod)(kube_pod_owner{cluster=~\"$cluster\",pod=~\"$pod\"})\r\n ),\"value\",\"$1\",\"pod\",\"(.*)\"),\"_\",\"Pod:\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n sum by(namespace)(kube_pod_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"}\r\n ),\"value\",\"$1\",\"namespace\",\"(.*)\"),\"_\",\"Namespace:\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n sum by(owner_kind,owner_name)( # Pod owner kind and name\r\n sum by(replicaset)(label_replace(\r\n sum by(owner_kind, owner_name)(\r\n kube_pod_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",owner_kind=\"replicaset\",pod=~\"$component\",pod=~\"$pod\"}\r\n ),\"replicaset\",\"$1\",\"owner_name\",\"(.*)\"))\r\n / on (replicaset) group_left(owner_kind, owner_name) \r\n sum by(owner_kind,owner_name,replicaset)(kube_replicaset_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",replicaset=~\"$component\"})\r\n or sum by(owner_kind, owner_name)(\r\n kube_pod_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",owner_kind!=\"replicaset\",pod=~\"$component\",pod=~\"$pod\"}\r\n )\r\n ),\"value\",\"$1\",\"owner_kind\",\"(.*)\"),\"_\",\"Type:\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n sum by(owner_kind,owner_name)( # Pod owner kind and name\r\n sum by(replicaset)(label_replace(\r\n sum by(owner_kind, owner_name)(\r\n kube_pod_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",owner_kind=\"replicaset\",pod=~\"$component\",pod=~\"$pod\"}\r\n ),\"replicaset\",\"$1\",\"owner_name\",\"(.*)\"))\r\n / on (replicaset) group_left(owner_kind, owner_name) \r\n sum by(owner_kind,owner_name,replicaset)(kube_replicaset_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",replicaset=~\"$component\"})\r\n or sum by(owner_kind, owner_name)(\r\n kube_pod_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",owner_kind!=\"replicaset\",pod=~\"$component\",pod=~\"$pod\"}\r\n )\r\n ),\"value\",\"$1\",\"owner_name\",\"(.*)\"),\"_\",\"Parent:\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n sum by(phase)(kube_pod_status_phase{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"} > 0\r\n ),\"value\",\"$1\",\"phase\",\"(.*)\"),\"_\",\"State:\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n sum by(phase)(kube_pod_status_phase{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"}) > 0 or\r\n label_replace(absent(present_over_time(sum(kube_pod_status_phase{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"})[$__rate_interval:])),\"phase\",\"deleted\",\"\",\"\"\r\n ),\"value\",\"$1\",\"phase\",\"(.*)\"),\"_\",\"State2:\",\"\",\"\") or\r\n vector(0)>0)", + "format": "table", + "hide": true, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "B" + } + ], + "title": " ", + "transformations": [ + { + "id": "convertFieldType", + "options": { + "conversions": [ + { + "destinationType": "boolean", + "targetField": "Time" + } + ], + "fields": {} + } + }, + { + "id": "groupingToMatrix", + "options": { + "columnField": "Time", + "rowField": "_", + "valueField": "value" + } + }, + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "_\\Time": "_", + "true": "." + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "fixed" + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": false + }, + "mappings": [ + { + "options": { + "0": { + "index": 5, + "text": "deleted" + }, + "1": { + "color": "red", + "index": 0, + "text": "failed" + }, + "2": { + "color": "yellow", + "index": 1, + "text": "pending" + }, + "3": { + "color": "green", + "index": 2, + "text": "running" + }, + "4": { + "color": "blue", + "index": 3, + "text": "succeeded" + }, + "5": { + "color": "orange", + "index": 4, + "text": "unknown" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 3, + "y": 6 + }, + "id": 64, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": true, + "rowHeight": 0.9, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by(_,value)(\r\n#label_replace(label_replace(\r\n# (vector(1)\r\n# ),\"value\",\"$pod\",\"\",\"\"),\"_\",\"Pod:\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n 1*sum by(phase)(kube_pod_status_phase{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\",phase=\"failed\"}) > 0 or\r\n 2*sum by(phase)(kube_pod_status_phase{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\",phase=\"pending\"}) > 0 or\r\n 3*sum by(phase)(kube_pod_status_phase{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\",phase=\"running\"}) > 0 or\r\n 4*sum by(phase)(kube_pod_status_phase{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\",phase=\"succeeded\"}) > 0 or\r\n 5*sum by(phase)(kube_pod_status_phase{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\",phase=\"unknown\"}) > 0 or\r\n 0*label_replace(absent(present_over_time(sum(kube_pod_status_phase{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"})[$__rate_interval:])),\"phase\",\"deleted\",\"\",\"\"\r\n ),\"value\",\"$1\",\"phase\",\"(.*)\"),\"_\",\"State2:\",\"\",\"\") or\r\n vector(0)>0)", + "format": "time_series", + "hide": false, + "instant": false, + "legendFormat": "{{value}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by(_,value)(\r\n#label_replace(label_replace(\r\n# (vector(1)\r\n# ),\"value\",\"$pod\",\"\",\"\"),\"_\",\"Pod:\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n (\r\n sum by(pod)(kube_pod_owner{cluster=~\"$cluster\",pod=~\"$pod\"})\r\n ),\"value\",\"$1\",\"pod\",\"(.*)\"),\"_\",\"Pod:\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n sum by(namespace)(kube_pod_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"}\r\n ),\"value\",\"$1\",\"namespace\",\"(.*)\"),\"_\",\"Namespace:\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n sum by(owner_kind,owner_name)( # Pod owner kind and name\r\n sum by(replicaset)(label_replace(\r\n sum by(owner_kind, owner_name)(\r\n kube_pod_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",owner_kind=\"replicaset\",pod=~\"$component\",pod=~\"$pod\"}\r\n ),\"replicaset\",\"$1\",\"owner_name\",\"(.*)\"))\r\n / on (replicaset) group_left(owner_kind, owner_name) \r\n sum by(owner_kind,owner_name,replicaset)(kube_replicaset_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",replicaset=~\"$component\"})\r\n or sum by(owner_kind, owner_name)(\r\n kube_pod_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",owner_kind!=\"replicaset\",pod=~\"$component\",pod=~\"$pod\"}\r\n )\r\n ),\"value\",\"$1\",\"owner_kind\",\"(.*)\"),\"_\",\"Type:\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n sum by(owner_kind,owner_name)( # Pod owner kind and name\r\n sum by(replicaset)(label_replace(\r\n sum by(owner_kind, owner_name)(\r\n kube_pod_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",owner_kind=\"replicaset\",pod=~\"$component\",pod=~\"$pod\"}\r\n ),\"replicaset\",\"$1\",\"owner_name\",\"(.*)\"))\r\n / on (replicaset) group_left(owner_kind, owner_name) \r\n sum by(owner_kind,owner_name,replicaset)(kube_replicaset_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",replicaset=~\"$component\"})\r\n or sum by(owner_kind, owner_name)(\r\n kube_pod_owner{cluster=~\"$cluster\",namespace=~\"$namespace\",owner_kind!=\"replicaset\",pod=~\"$component\",pod=~\"$pod\"}\r\n )\r\n ),\"value\",\"$1\",\"owner_name\",\"(.*)\"),\"_\",\"Parent:\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n sum by(phase)(kube_pod_status_phase{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"} > 0\r\n ),\"value\",\"$1\",\"phase\",\"(.*)\"),\"_\",\"State:\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n sum by(phase)(kube_pod_status_phase{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"}) > 0 or\r\n label_replace(absent(present_over_time(sum(kube_pod_status_phase{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"})[$__rate_interval:])),\"phase\",\"deleted\",\"\",\"\"\r\n ),\"value\",\"$1\",\"phase\",\"(.*)\"),\"_\",\"State2:\",\"\",\"\") or\r\n vector(0)>0)", + "format": "table", + "hide": true, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "B" + } + ], + "title": "State timeline", + "transformations": [ + { + "disabled": true, + "id": "convertFieldType", + "options": { + "conversions": [ + { + "destinationType": "boolean", + "targetField": "Time" + } + ], + "fields": {} + } + }, + { + "disabled": true, + "id": "groupingToMatrix", + "options": { + "columnField": "Time", + "rowField": "_", + "valueField": "value" + } + }, + { + "disabled": true, + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "_\\Time": "_", + "true": "." + } + } + } + ], + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "milli-cores", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 40 + }, + { + "color": "red", + "value": 60 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "CPU Limits (cores)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "super-light-purple", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "auto" + }, + { + "id": "custom.axisColorMode", + "value": "text" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Usage (cores)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Usage (milli-cores)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Max Throttled (%)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "thresholds", + "seriesBy": "max" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "custom.axisLabel", + "value": "Throttle Percent" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 9 + }, + "id": 43, + "links": [ + { + "targetBlank": true, + "title": "Open K8s / Compute Resources / Pod", + "url": "/d/6581e46e4e5c7ba40a07646395ef6738/kubernetes-compute-resources-pod?${__url_time_range}&${cluster:queryparam}&var-namespace=${podnamespace}&${pod:queryparam}" + } + ], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "repeat": "container", + "repeatDirection": "v", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\n#(label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container=~\"$container\"}[$__rate_interval]))*1000,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\") \r\n# and label_replace(quantile_over_time(0.95,sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container=~\"$container\"}[$__rate_interval]))[3d:]) < 0.2,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\")) # Show milli-cores if rate below 0.2 cores\r\n# CPU Time (cores version, if >= 0.2 cores)\r\n#or \r\n(label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",pod=~\"$pod\",container=~\"$container\"}[$__rate_interval])),\"_\",\"CPU Usage (milli-cores)\",\"\",\"\") *1000\r\n #and label_replace(quantile_over_time(0.95,sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container=~\"$container\"}[$__rate_interval]))[3d:]) >= 0.2,\"_\",\"CPU Usage (cores)\",\"\",\"\")\r\n ) # Show in cores if rate at or above 0.2 cores\r\n# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(quantile_over_time(0.95,sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container=~\"$container\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\n# Sum of all limits defined, in Cores\r\nor label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",pod=~\"$pod\",container=~\"$container\",resource=\"cpu\"}),\"_\",\"CPU Limits (milli-cores)\",\"\",\"\")*1000\r\n# CPU Throttling:\r\nor label_replace(100*(max(\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",pod=~\"$pod\",container=~\"$container\"}[10m])\r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",pod=~\"$pod\",container=~\"$container\"}[10m])\r\n )),\"_\",\"CPU Max Throttled (%)\",\"\",\"\")\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "CPU for [$container]", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "MB", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "orange", + "value": 90 + }, + { + "color": "red", + "value": 95 + }, + { + "color": "dark-red", + "value": 99 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Mem Working Bytes (GB)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mem Working Bytes (MB)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mem Max Usage vs Limit (%)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "thresholds", + "seriesBy": "max" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "custom.axisLabel" + }, + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "Memory Limits .*" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 9 + }, + "id": 45, + "links": [ + { + "targetBlank": true, + "title": "Open K8s / Compute Resources / Pod", + "url": "/d/6581e46e4e5c7ba40a07646395ef6738/kubernetes-compute-resources-pod?${__url_time_range}&${cluster:queryparam}&var-namespace=${podnamespace}&${pod:queryparam}" + } + ], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "repeat": "container", + "repeatDirection": "v", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory Usage (MB version)\r\n(label_replace(sum(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",pod=~\"$pod\",container=~\"$container\"})/(1024*1024),\"_\",\"Mem Working Bytes (MB)\",\"\",\"\") #and label_replace(max_over_time(sum(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container=~\"$container\"})[3d:])/(1024*1024) < 512,\"_\",\"Mem Working Bytes (MB)\",\"\",\"\")\r\n)\r\n# Memory Usage (GB version)\r\n#or (label_replace(sum(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container=~\"$container\"})/(1024*1024*1024),\"_\",\"Mem Working Bytes (GB)\",\"\",\"\") and label_replace(quantile_over_time(0.95,sum(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container=~\"$container\"})[3d:])/(1024*1024) >= 512,\"_\",\"Mem Working Bytes (GB)\",\"\",\"\"))\r\n### MB vs GB cut-off\r\n##or label_replace(quantile_over_time(0.95,sum(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container=~\"$container\"})[3d:])/(1024*1024),\"_\",\"Mem Max Over Time\",\"\",\"\")\r\n# Sum of all limits defined, in Cores\r\nor (label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",pod=~\"$pod\",container=~\"$container\",resource=\"memory\"}),\"_\",\"Memory Limits (MB)\",\"\",\"\") / (1024*1024) #and label_replace(quantile_over_time(0.95,sum(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container=~\"$container\"})[3d:])/(1024*1024) < 512,\"_\",\"Memory Limits (MB)\",\"\",\"\")\r\n)\r\n#or (label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container=~\"$container\",resource=\"memory\"}),\"_\",\"Memory Limits (GB)\",\"\",\"\") / (1024*1024*1024) and label_replace(quantile_over_time(0.95,sum(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container=~\"$container\"})[3d:])/(1024*1024) >= 512,\"_\",\"Memory Limits (GB)\",\"\",\"\"))\r\n# Max Mem % Usage:\r\nor label_replace(100*(max(\r\n max_over_time((max by(container)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",pod=~\"$pod\",container=~\"$container\"}))[10m:])\r\n / max by(container)(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",pod=~\"$pod\",container=~\"$container\",resource=\"memory\"})\r\n )),\"_\",\"Mem Max Usage vs Limit (%)\",\"\",\"\")\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Memory for [$container]", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 13, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Logs\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 6, + "panels": [], + "title": "Kube Events", + "type": "row" + }, + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "yellow", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Reason" + }, + "properties": [ + { + "id": "custom.width", + "value": 120 + }, + { + "id": "custom.align", + "value": "center" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "Failed": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ] + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Count" + }, + "properties": [ + { + "id": "custom.width", + "value": 80 + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.width", + "value": 180 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Message" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Count" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "color", + "value": { + "mode": "continuous-BlPu" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 55, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "LastSeen" + } + ] + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "azureLogAnalytics": { + "query": "KubeEvents\r\n| where TimeGenerated > $__timeFrom() and TimeGenerated <= $__timeTo\r\n| where ClusterName == '$cluster'\r\n//| where Name matches regex '${component:raw}'\r\n| where Name matches regex '$pod'\r\n//| order by TimeGenerated desc\r\n| order by LastSeen desc, FirstSeen desc, TimeGenerated desc\r\n//| project-rename PodName = Name\r\n//| project PodName, Reason, Message, Count, FirstSeen, LastSeen\r\n| project FirstSeen, LastSeen, Count, Reason, Message\r\n| take $logRowLimit", + "resources": [ + "/subscriptions/af342bf1-1ace-41df-902c-47921400551b" + ], + "resultFormat": "table" + }, + "azureMonitor": { + "allowedTimeGrainsMs": [], + "timeGrain": "auto" + }, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "queryType": "Azure Log Analytics", + "refId": "A" + } + ], + "title": "Kube Events entries (for [$pod] up to $logRowLimit events)", + "type": "table" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 2, + "panels": [], + "title": "Container Logs", + "type": "row" + }, + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.width", + "value": 180 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "STD" + }, + "properties": [ + { + "id": "custom.width", + "value": 30 + }, + { + "id": "mappings", + "value": [ + { + "options": { + "ERR": { + "color": "orange", + "index": 0 + } + }, + "type": "value" + } + ] + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 13, + "w": 24, + "x": 0, + "y": 28 + }, + "id": 62, + "maxPerRow": 3, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "9.5.13", + "repeat": "container", + "repeatDirection": "h", + "targets": [ + { + "azureLogAnalytics": { + "query": "let startTime = datetime(${__from:date});\r\nlet nodes = ContainerNodeInventory // ID computers in selected clusters:\r\n| where TimeGenerated >= startTime | summarize by Computer, _ResourceId\r\n| extend Cluster = substring(_ResourceId,strlen(_ResourceId)-indexof(reverse(_ResourceId),'/'))\r\n| project-reorder Cluster, Computer | where Cluster == '$cluster' | take 10 | project Computer; //, Cluster; // nodes;\r\nlet containerInv = ContainerInventory // Get ContainerIds and pod names\r\n| where TimeGenerated >= startTime | join kind=inner nodes on Computer | where ContainerHostname == '$pod'\r\n| summarize by ContainerHostname, Computer, ContainerID, Name | take 100 | project-rename Pod = ContainerHostname \r\n| extend ContainerName = replace_regex(Name, 'k8s_(.*)_${pod}_.*',@'\\1') \r\n| where ContainerName == '${container:raw}'\r\n| project Pod, ContainerName, ContainerID; // containerInv\r\nlet containerIds = containerInv | project ContainerID;\r\nContainerLog\r\n//| where TimeGenerated >= startTime \r\n| where TimeGenerated > $__timeFrom and TimeGenerated <= $__timeTo\r\n| where Computer in (nodes)\r\n| where ContainerID in (containerIds)\r\n| join kind=inner hint.strategy=shuffle containerInv on ContainerID | project-away ContainerID1, ContainerID, TenantId, SourceSystem, Type, _ResourceId, TimeOfCommand\r\n//| join kind=inner nodes on Computer | project-away Computer1 | project-rename Node = Computer\r\n| extend STD = case(LogEntrySource == 'stdout', 'OUT', LogEntrySource == 'stderr', 'ERR', '???')\r\n//| project TimeGenerated, LogEntrySource, \r\n| order by TimeGenerated desc\r\n| project STD, LogEntry, TimeGenerated //, Node, Cluster\r\n| take $logRowLimit", + "resources": [ + "/subscriptions/af342bf1-1ace-41df-902c-47921400551b" + ], + "resultFormat": "table" + }, + "azureMonitor": { + "allowedTimeGrainsMs": [], + "timeGrain": "auto" + }, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "queryType": "Azure Log Analytics", + "refId": "A" + } + ], + "title": "Container logs (for [$container], latest $logRowLimit rows)", + "type": "table" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_node_status_condition", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "kube_node_status_condition", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*cluster=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "hide": 0, + "includeAll": true, + "multi": true, + "name": "namespace", + "options": [], + "query": { + "query": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": ".*", + "current": { + "selected": true, + "text": "All", + "value": "^(.*)$" + }, + "description": "Defines the service Component this report focuses on.", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "component", + "options": [ + { + "selected": true, + "text": "All", + "value": "^(.*)$" + }, + { + "selected": false, + "text": "AKRI", + "value": "^(akri-).*" + }, + { + "selected": false, + "text": "Bluefin", + "value": "^(bf-|bluefin-).*" + }, + { + "selected": false, + "text": "E4I", + "value": "(^(opc-ua-|edge-application-supervisor).*|.*-opc-ua-.*)" + }, + { + "selected": false, + "text": "E4K", + "value": "^(azedge-).*" + }, + { + "selected": false, + "text": "Symphony", + "value": "^symphony-.*" + }, + { + "selected": false, + "text": "AzMon", + "value": "^(ama-|azuremonitor).*" + }, + { + "selected": false, + "text": "OBS", + "value": "^(obs|lok|flu|ote|pro|tem).*" + } + ], + "query": "All : ^(.*)$,AKRI : ^(akri-).*,Bluefin : ^(bf-|bluefin-).*,E4I : (^(opc-ua-|edge-application-supervisor).*|.*-opc-ua-.*),E4K : ^(azedge-).*,Symphony : ^symphony-.*,AzMon : ^(ama-|azuremonitor).*,OBS : ^(obs|lok|flu|ote|pro|tem).*", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "container_cpu_usage_seconds_total{container=\"\",cpu=\"total\",cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\"}", + "description": "The pod the report focuses on", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "pod", + "options": [], + "query": { + "query": "container_cpu_usage_seconds_total{container=\"\",cpu=\"total\",cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\"}", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "/.*pod=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "container_cpu_usage_seconds_total{container=\"\",cpu=\"total\",cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"}", + "description": "Used to drilldown into K8s reports that require single namespace value", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "podnamespace", + "options": [], + "query": { + "query": "container_cpu_usage_seconds_total{container=\"\",cpu=\"total\",cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"}", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_pod_container_info{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"}", + "hide": 2, + "includeAll": true, + "multi": true, + "name": "container", + "options": [], + "query": { + "query": "kube_pod_container_info{cluster=~\"$cluster\",namespace=~\"$namespace\",pod=~\"$component\",pod=~\"$pod\"}", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "/.*container=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": { + "selected": true, + "text": "10", + "value": "10" + }, + "description": "How many rows to limit log queries to", + "hide": 0, + "includeAll": false, + "label": "Log Row Limit", + "multi": false, + "name": "logRowLimit", + "options": [ + { + "selected": true, + "text": "10", + "value": "10" + }, + { + "selected": false, + "text": "50", + "value": "50" + }, + { + "selected": false, + "text": "100", + "value": "100" + }, + { + "selected": false, + "text": "500", + "value": "500" + }, + { + "selected": false, + "text": "1000", + "value": "1000" + } + ], + "query": "10,50,100,500,1000", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "aio-health-infra-pod", + "uid": "wlCiLDq4k", + "version": 33, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-health-infra-workload-1698853576137.json b/samples/dashboard/grafana-dashboards/aio-health-infra-workload-1698853576137.json new file mode 100644 index 0000000..3744bf9 --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-health-infra-workload-1698853576137.json @@ -0,0 +1,2458 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "panel", + "id": "piechart", + "name": "Pie chart", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "state-timeline", + "name": "State timeline", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n Azure Edge Services - Infrastructure Health\n
\n
\n   Infrastructure Workload Health by Component\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 133, + "panels": [], + "repeat": "component", + "repeatDirection": "h", + "title": "$component", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": false + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#808080", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 4 + }, + "id": 189, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.9, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Workload Readiness health\r\n############################\r\nlabel_replace(min(\r\navg(label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n label_replace(label_join(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n / label_replace(label_join(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n) by (workload) >=0 \r\n) or vector(-1),\"_\",\"Workload Readiness\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Restart Health:\r\n############################\r\nlabel_replace(\r\n sgn(sum_over_time(sum(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[10m:1m]\r\n )*60)[1h:]) > 5) * 0.0 # RED: Cumulative restarts over X(5) time greater than Y(1h)\r\n or (max(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[5m:1m]\r\n )*60*5) > 0) * 0.5 # YELLOW: restarts detected but below Red threshold\r\n or sgn(max(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}\r\n + 1 >= 0))\r\n #or vector(1) # Healthy\r\n ,\"_\",\"Container Restart Health\",\"\",\"\")\r\n## uncomment below to t-shoot this health metric\r\n# or label_replace(sum_over_time(sum(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[10m:1m])*60)[1h:]),\"_\",\"Total-restarts-over-time\",\"\",\"\")\r\n# or label_replace((max(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[5m:1m])*60*5) without (__name__,uid,instance,job) > 0),\"_\",\"restart\",\"\",\"\") # Base query for counting restarts\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container CPU top-level health\r\n################################\r\nlabel_replace(\r\nmin(sgn( # Check for throttling > N indicating container is exceeding its CPU limits\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m]) \r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m])\r\n >= 0.60) # If throttle create is greater than this percentage, we'll multiply sgn by 0.5 to show as error (or warning depending on threshold coloring)\r\n ) # by (namespace,container) # These are commented out for top-level\r\n * 0.0\r\nor\r\nmin(sgn( # Check for throttling > N indicating container is exceeding its CPU limits\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m]) \r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m])\r\n >= 0.40) # If throttle create is greater than this percentage, we'll multiply sgn by 0.5 to show as error (or warning depending on threshold coloring)\r\n ) # by (namespace,container) # These are commented out for top-level\r\n * 0.5\r\nor\r\nmin( # Check to see if container is missing CPU Limits configuration\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"cpu\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n ) #by (namespace,container) # These are commented out for top-level\r\n,\"_\",\"Container CPU Health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Memory Health:\r\n###########################\r\nlabel_replace(\r\nmin( # Look for high memory utilization\r\n 0.0 * sgn((\r\n max(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container)\r\n / min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"memory\",pod=~\"${component:raw}\"}) by (namespace, container)\r\n ) >= .95) or # show health state of 0 if container memory utilization >= 95%\r\n 0.5 * sgn((\r\n max(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container)\r\n / min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"memory\",pod=~\"${component:raw}\"}) by (namespace, container)\r\n ) >= .80) or # show health state of 0.5 if container memory utilization >= 80%\r\n vector(0)>0\r\n) #by (container) \r\nor\r\nmin( # Look for missing limits which we will show as 0 if missing\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"memory\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n) #by (container) \r\n,\"_\",\"Container Memory health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Health Summary", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "max(rate(container_cpu_usage_seconds_total{namespace=~\"alice-springs|symphony-k8s-system\",container=\"\",cpu=\"total\"}[5m])*300 > 0) ": "POD CPU (max)", + "min( # Workload ready percents (for deployment, daemonset, replicaset, and statefulset)\r\n label_replace(label_join(\r\n {job=\"kube-state-metrics\",namespace=~\"alice-springs|symphony-k8s-system\",\r\n __name__=~\"kube_(deployment|daemonset|replicaset|statefulset)_status_(replicas_ready|ready_replicas|number_ready)\"}\r\n ,\"workload\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n / label_replace(label_join(\r\n {job=\"kube-state-metrics\",namespace=~\"alice-springs|symphony-k8s-system\",\r\n __name__=~\"kube_(deployment|daemonset|replicaset|statefulset)_status_(replicas|desired_number_scheduled)\"}\r\n ,\"workload\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n) #by (workloadType) #namespace) #, workloadType) #, workload)": "Workload ready health" + } + } + } + ], + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 20 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 6, + "y": 4 + }, + "id": 174, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(sum ( # by(workloadType) (\r\n#min(\r\n# label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n label_replace(label_join(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n),\"_\",\"Ready\",\"\",\"\")\r\n# / label_replace(label_join(\r\n# kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\"$namespace\",daemonset=~\"${component:raw}\"} or\r\n# kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\"$namespace\",deployment=~\"${component:raw}\"} or\r\n# kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\"$namespace\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n# ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n#) by (workload) >=0 ", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#min(\r\n# label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n# label_replace(label_join(\r\n# kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",deployment=~\"${component:raw}\"} or\r\n# kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",daemonset=~\"${component:raw}\"} or\r\n# kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n# / label_replace(label_join(\r\n label_replace(sum(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n ),\"_\",\"Requested\",\"\",\"\")\r\n# ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n#) by (workload) >=0 ", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Workloads", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 8, + "y": 4 + }, + "id": 184, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor label_replace(vector(0),\"status\",\"Ready\",\"\",\"\")\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "DaemonSets", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 10, + "y": 4 + }, + "id": 185, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor label_replace(vector(0),\"status\",\"Ready\",\"\",\"\") # this is to zero if no workloads of this type exist\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "Deployments", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 12, + "y": 4 + }, + "id": 186, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor \r\nlabel_replace(vector(0),\"status\",\"Ready\",\"\",\"\")\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "StatefulSets", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 1 + }, + { + "color": "dark-orange", + "value": 5 + }, + { + "color": "red", + "value": 10 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 14, + "y": 4 + }, + "id": 187, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Container Restarts\r\nlabel_replace(ceil(sum_over_time(sum(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[10m:1m])*60)[1h:])),\"_\",\"Restarts\",\"\",\"\")\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 40 + }, + { + "color": "red", + "value": 60 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percent containers with CPU Limits (%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "super-light-purple", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Usage (milli-cores)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisColorMode", + "value": "series" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Max Throttled (%)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "thresholds", + "seriesBy": "max" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 4 + }, + "id": 282, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\n(label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))*1000,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\") )\r\n# Percent of containers with limits defined\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"Percent containers with CPU Limits (%)\",\"\",\"\")\r\n# CPU Throttling:\r\nor label_replace(100*(max(\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n )),\"_\",\"CPU Max Throttled (%)\",\"\",\"\")\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(quantile_over_time(0.95,sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\nvector(0)>0\r\n# Sum of all limits defined, in Cores\r\nor label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# WIP:\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"WIP-PERCENT_WITH_LIMITS\",\"\",\"\")\r\nor label_replace(count(\r\n kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"})\r\n ,\"_\",\"WIP-NUMERATOR\",\"\",\"\")\r\nor label_replace(count(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) #without(cluster,container,cpu,id,image,instance,job,name,namespace,pod)\r\n ,\"_\",\"WIP-DENOMINATOR\",\"\",\"\")\r\n# ", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "CPU", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 80 + }, + { + "color": "orange", + "value": 85 + }, + { + "color": "red", + "value": 90 + }, + { + "color": "dark-red", + "value": 95 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percent containers with Memory Limits (%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mem Working Bytes (MB)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisColorMode", + "value": "series" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mem Max Usage vs Limit (%)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "thresholds", + "seriesBy": "max" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 4 + }, + "id": 283, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory Usage (MB version)\r\n(label_replace(sum(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"Mem Working Bytes (MB)\",\"\",\"\") )\r\n# Percent containers with limits\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"memory\"}) /\r\n count(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}) *100\r\n ,\"_\",\"Percent containers with Memory Limits (%)\",\"\",\"\")\r\n# Max Mem % Usage:\r\nor label_replace(100*(max(\r\n max_over_time((max by(container)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}))[10m:])\r\n / max by(container)(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"memory\"})\r\n )),\"_\",\"Mem Max Usage vs Limit (%)\",\"\",\"\")\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(quantile_over_time(0.95,sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\nvector(0)>0\r\n# Sum of all limits defined, in Cores\r\nor label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# WIP:\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"WIP-PERCENT_WITH_LIMITS\",\"\",\"\")\r\nor label_replace(count(\r\n kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"})\r\n ,\"_\",\"WIP-NUMERATOR\",\"\",\"\")\r\nor label_replace(count(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) #without(cluster,container,cpu,id,image,instance,job,name,namespace,pod)\r\n ,\"_\",\"WIP-DENOMINATOR\",\"\",\"\")\r\n# ", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Memory", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 48 + }, + "id": 164, + "panels": [], + "title": " ", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 49 + }, + "id": 150, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Infrastructure Workload Health by Namespace\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 51 + }, + "id": 238, + "panels": [], + "repeat": "namespace4workloads", + "repeatDirection": "h", + "title": "$namespace4workloads", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": false + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#505050" + }, + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 52 + }, + "id": 240, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.9, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Workload Readiness health\r\n############################\r\nlabel_replace(min(\r\navg(label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n label_replace(label_join(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"} or\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",daemonset=~\".*\"} or\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",statefulset=~\".*\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n / label_replace(label_join(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",daemonset=~\".*\"} or\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"} or\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",statefulset=~\".*\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n) by (workload) >=0 \r\n) or vector(-1),\"_\",\"Workload Readiness\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Restart Health:\r\n############################\r\nlabel_replace(\r\n sgn(sum_over_time(sum(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\"}[10m:1m]\r\n )*60)[1h:]) > 5) * 0.0 # RED: Cumulative restarts over X(5) time greater than Y(1h)\r\n or (max(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\"}[5m:1m]\r\n )*60*5) > 0) * 0.5 # YELLOW: restarts detected but below Red threshold\r\n or sgn(max(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\"}\r\n + 1 >= 0))\r\n #or vector(1) # Healthy\r\n ,\"_\",\"Container Restart Health\",\"\",\"\")\r\n## uncomment below to t-shoot this health metric\r\n# or label_replace(sum_over_time(sum(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[10m:1m])*60)[1h:]),\"_\",\"Total-restarts-over-time\",\"\",\"\")\r\n# or label_replace((max(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[5m:1m])*60*5) without (__name__,uid,instance,job) > 0),\"_\",\"restart\",\"\",\"\") # Base query for counting restarts\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container CPU top-level health\r\n################################\r\nlabel_replace(\r\nmin(sgn( # Check for throttling > N indicating container is exceeding its CPU limits\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",container!=\"\",pod=~\".*\"}[10m]) \r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",container!=\"\",pod=~\".*\"}[10m])\r\n >= 0.60) # If throttle create is greater than this percentage, we'll multiply sgn by 0.5 to show as error (or warning depending on threshold coloring)\r\n ) # by (namespace,container) # These are commented out for top-level\r\n * 0.0\r\nor\r\nmin(sgn( # Check for throttling > N indicating container is exceeding its CPU limits\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",container!=\"\",pod=~\".*\"}[10m]) \r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",container!=\"\",pod=~\".*\"}[10m])\r\n >= 0.40) # If throttle create is greater than this percentage, we'll multiply sgn by 0.5 to show as error (or warning depending on threshold coloring)\r\n ) # by (namespace,container) # These are commented out for top-level\r\n * 0.5\r\nor\r\nmin( # Check to see if container is missing CPU Limits configuration\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",container!=\"\",resource=\"cpu\",pod=~\".*\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",container!=\"\",pod=~\".*\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n ) #by (namespace,container) # These are commented out for top-level\r\n,\"_\",\"Container CPU Health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Memory Health:\r\n###########################\r\nlabel_replace(\r\nmin( # Look for high memory utilization\r\n 0.0 * sgn((\r\n max(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",container!=\"\"}) by (namespace,container)\r\n / min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",container!=\"\",resource=\"memory\"}) by (namespace, container)\r\n ) >= .95) or # show health state of 0 if container memory utilization >= 95%\r\n 0.5 * sgn((\r\n max(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",container!=\"\"}) by (namespace,container)\r\n / min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",container!=\"\",resource=\"memory\"}) by (namespace, container)\r\n ) >= .80) or # show health state of 0.5 if container memory utilization >= 80%\r\n vector(0)>0\r\n) #by (container) \r\nor\r\nmin( # Look for missing limits which we will show as 0 if missing\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",container!=\"\",resource=\"memory\",pod=~\".*\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",container!=\"\",pod=~\".*\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n) #by (container) \r\n,\"_\",\"Container Memory health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Health Summary", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "max(rate(container_cpu_usage_seconds_total{namespace=~\"alice-springs|symphony-k8s-system\",container=\"\",cpu=\"total\"}[5m])*300 > 0) ": "POD CPU (max)", + "min( # Workload ready percents (for deployment, daemonset, replicaset, and statefulset)\r\n label_replace(label_join(\r\n {job=\"kube-state-metrics\",namespace=~\"alice-springs|symphony-k8s-system\",\r\n __name__=~\"kube_(deployment|daemonset|replicaset|statefulset)_status_(replicas_ready|ready_replicas|number_ready)\"}\r\n ,\"workload\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n / label_replace(label_join(\r\n {job=\"kube-state-metrics\",namespace=~\"alice-springs|symphony-k8s-system\",\r\n __name__=~\"kube_(deployment|daemonset|replicaset|statefulset)_status_(replicas|desired_number_scheduled)\"}\r\n ,\"workload\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n) #by (workloadType) #namespace) #, workloadType) #, workload)": "Workload ready health" + } + } + } + ], + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red" + }, + { + "color": "green", + "value": 20 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 6, + "y": 52 + }, + "id": 243, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(sum ( # by(workloadType) (\r\n#min(\r\n# label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n label_replace(label_join(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",daemonset=~\".*\"} or\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"} or\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",statefulset=~\".*\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n),\"_\",\"Ready\",\"\",\"\")\r\n# / label_replace(label_join(\r\n# kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\"$namespace\",daemonset=~\".*\"} or\r\n# kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\"$namespace\",deployment=~\".*\"} or\r\n# kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\"$namespace\",statefulset=~\".*\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n# ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n#) by (workload) >=0 ", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#min(\r\n# label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n# label_replace(label_join(\r\n# kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",deployment=~\".*\"} or\r\n# kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",daemonset=~\".*\"} or\r\n# kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",statefulset=~\".*\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n# / label_replace(label_join(\r\n label_replace(sum(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",daemonset=~\".*\"} or\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"} or\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",statefulset=~\".*\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n ),\"_\",\"Requested\",\"\",\"\")\r\n# ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n#) by (workload) >=0 ", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Workloads", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 8, + "y": 52 + }, + "id": 247, + "links": [ + { + "targetBlank": true, + "title": "AKS Reports - k8s / Compute Resources / Workload", + "url": "/d/a164a7f0339f99e89cea5cb47e9b6738/kubernetes-compute-resources-workload?${__url_time_range}&${cluster:queryparam}&var-namespace=${namespace4workloads}&var-type=daemonset" + } + ], + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",daemonset=~\".*\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",daemonset=~\".*\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",daemonset=~\".*\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor label_replace(vector(0),\"status\",\"Ready\",\"\",\"\")\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "DaemonSets", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 10, + "y": 52 + }, + "id": 252, + "links": [ + { + "targetBlank": true, + "title": "AKS Reports - k8s / Compute Resources / Workload", + "url": "/d/a164a7f0339f99e89cea5cb47e9b6738/kubernetes-compute-resources-workload?${__url_time_range}&${cluster:queryparam}&var-namespace=${namespace4workloads}&var-type=deployment" + } + ], + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor label_replace(vector(0),\"status\",\"Ready\",\"\",\"\") # this is to zero if no workloads of this type exist\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "Deployments", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 12, + "y": 52 + }, + "id": 258, + "links": [ + { + "targetBlank": true, + "title": "AKS Reports - k8s / Compute Resources / Workload", + "url": "/d/a164a7f0339f99e89cea5cb47e9b6738/kubernetes-compute-resources-workload?${__url_time_range}&${cluster:queryparam}&var-namespace=${namespace4workloads}&var-type=statefulset" + } + ], + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",statefulset=~\".*\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",statefulset=~\".*\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",statefulset=~\".*\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor \r\nlabel_replace(vector(0),\"status\",\"Ready\",\"\",\"\")\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",deployment=~\".*\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "StatefulSets", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 1 + }, + { + "color": "dark-orange", + "value": 5 + }, + { + "color": "red", + "value": 10 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 14, + "y": 52 + }, + "id": 265, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Container Restarts\r\nlabel_replace(ceil(sum_over_time(sum(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\"}[10m:1m])*60)[1h:])),\"_\",\"Restarts\",\"\",\"\")\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "#EAB839", + "value": 40 + }, + { + "color": "red", + "value": 60 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percent containers with CPU Limits (%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "super-light-purple", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Usage (milli-cores)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisColorMode", + "value": "series" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Max Throttled (%)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "thresholds", + "seriesBy": "max" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 52 + }, + "id": 275, + "links": [ + { + "targetBlank": true, + "title": "AKS Reports - K8s / Compute Resources / Namespace", + "url": "/d/85a562078cdf77779eaa1add43cc6738/kubernetes-compute-resources-namespace-pods?${__url_time_range}&${cluster:queryparam}&var-namespace=${namespace4workloads}" + }, + { + "targetBlank": true, + "title": "AKS Reports - K8s / Compute Resources / Pod", + "url": "/d/6581e46e4e5c7ba40a07646395ef6738/kubernetes-compute-resources-pod?${__url_time_range}&${cluster:queryparam}&var-namespace=${namespace4workloads}" + } + ], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\n(label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}[$__rate_interval]))*1000,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\") )\r\n# Percent of containers with limits defined\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"Percent containers with CPU Limits (%)\",\"\",\"\")\r\n# CPU Throttling:\r\nor label_replace(100*(max(\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}[10m])\r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}[10m])\r\n )),\"_\",\"CPU Max Throttled (%)\",\"\",\"\")\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(quantile_over_time(0.95,sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\nvector(0)>0\r\n# Sum of all limits defined, in Cores\r\nor label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# WIP:\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"WIP-PERCENT_WITH_LIMITS\",\"\",\"\")\r\nor label_replace(count(\r\n kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"})\r\n ,\"_\",\"WIP-NUMERATOR\",\"\",\"\")\r\nor label_replace(count(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) #without(cluster,container,cpu,id,image,instance,job,name,namespace,pod)\r\n ,\"_\",\"WIP-DENOMINATOR\",\"\",\"\")\r\n# ", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "CPU", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "#EAB839", + "value": 80 + }, + { + "color": "orange", + "value": 85 + }, + { + "color": "red", + "value": 90 + }, + { + "color": "dark-red", + "value": 95 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percent containers with Memory Limits (%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mem Working Bytes (MB)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisColorMode", + "value": "series" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mem Max Usage vs Limit (%)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "thresholds", + "seriesBy": "max" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 52 + }, + "id": 281, + "links": [ + { + "targetBlank": true, + "title": "AKS Reports - K8s / Compute Resources / Namespace", + "url": "/d/85a562078cdf77779eaa1add43cc6738/kubernetes-compute-resources-namespace-pods?${__url_time_range}&${cluster:queryparam}&var-namespace=${namespace4workloads}" + }, + { + "targetBlank": true, + "title": "AKS Reports - K8s / Compute Resources / Pod", + "url": "/d/6581e46e4e5c7ba40a07646395ef6738/kubernetes-compute-resources-pod?${__url_time_range}&${cluster:queryparam}&var-namespace=${namespace4workloads}" + } + ], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory Usage (MB version)\r\n(label_replace(sum(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"})/(1024*1024),\"_\",\"Mem Working Bytes (MB)\",\"\",\"\") )\r\n# Percent containers with limits\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"memory\"}) /\r\n count(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}) *100\r\n ,\"_\",\"Percent containers with Memory Limits (%)\",\"\",\"\")\r\n# Max Mem % Usage:\r\nor label_replace(100*(max(\r\n max_over_time((max by(container)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}))[10m:])\r\n / max by(container)(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"memory\"})\r\n )),\"_\",\"Mem Max Usage vs Limit (%)\",\"\",\"\")\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(quantile_over_time(0.95,sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\nvector(0)>0\r\n# Sum of all limits defined, in Cores\r\nor label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# WIP:\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"WIP-PERCENT_WITH_LIMITS\",\"\",\"\")\r\nor label_replace(count(\r\n kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"})\r\n ,\"_\",\"WIP-NUMERATOR\",\"\",\"\")\r\nor label_replace(count(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) #without(cluster,container,cpu,id,image,instance,job,name,namespace,pod)\r\n ,\"_\",\"WIP-DENOMINATOR\",\"\",\"\")\r\n# ", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Memory", + "type": "timeseries" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 2, + "includeAll": false, + "label": "datasource", + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_node_status_condition", + "description": "PAS Cluster to view", + "hide": 0, + "includeAll": false, + "label": "cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "kube_node_status_condition", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*cluster=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "hide": 0, + "includeAll": true, + "label": "namespaces", + "multi": true, + "name": "namespace", + "options": [], + "query": { + "query": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_pod_status_phase{cluster=~\"$cluster\",namespace=~\"$namespace\"}", + "description": "Subset of existing namespace selection to filter only those with workloads", + "hide": 2, + "includeAll": true, + "multi": true, + "name": "namespace4workloads", + "options": [], + "query": { + "query": "kube_pod_status_phase{cluster=~\"$cluster\",namespace=~\"$namespace\"}", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": { + "selected": false, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "description": "PAS Components", + "hide": 0, + "includeAll": true, + "label": "Component", + "multi": true, + "name": "component", + "options": [ + { + "selected": true, + "text": "All", + "value": "$__all" + }, + { + "selected": false, + "text": "AIO-DataProcessor", + "value": "^aio-(dp-).*" + }, + { + "selected": false, + "text": "AIO-MQ", + "value": "^aio-(mq-).*" + }, + { + "selected": false, + "text": "AIO-LayeredNetworkManagement", + "value": "^(aio-lnm-|lnm).*" + }, + { + "selected": false, + "text": "AIO-OPCUABroker", + "value": "^aio-(opc-).*" + }, + { + "selected": false, + "text": "AIO-Orchestrator", + "value": "^aio-(cert-|orc-).*" + }, + { + "selected": false, + "text": "AzMon", + "value": "^(ama-|azuremonitor).*" + }, + { + "selected": false, + "text": "OLD-AKRI", + "value": "^(akri-).*" + }, + { + "selected": false, + "text": "OLD-OBS", + "value": "^(obs|lok|flu|otel|pro|tem).*" + }, + { + "selected": false, + "text": "AIO-3P-Support", + "value": "^(aio-otel|telegraf).*" + } + ], + "query": "AIO-DataProcessor : ^aio-(dp-).*,AIO-MQ : ^aio-(mq-).*,AIO-LayeredNetworkManagement : ^(aio-lnm-|lnm).*,AIO-OPCUABroker : ^aio-(opc-).*,AIO-Orchestrator : ^aio-(cert-|orc-).*,AzMon : ^(ama-|azuremonitor).*,OLD-AKRI : ^(akri-).*,OLD-OBS : ^(obs|lok|flu|otel|pro|tem).*,AIO-3P-Support : ^(aio-otel|telegraf).*", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-2d", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "aio-health-infra-workload", + "uid": "E5cCeHj4z", + "version": 53, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-health-service-akri-1698853585126.json b/samples/dashboard/grafana-dashboards/aio-health-service-akri-1698853585126.json new file mode 100644 index 0000000..a88d83e --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-health-service-akri-1698853585126.json @@ -0,0 +1,3845 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + }, + { + "name": "DS_AZURE_MONITOR", + "label": "Azure Monitor", + "description": "", + "type": "datasource", + "pluginId": "grafana-azure-monitor-datasource", + "pluginName": "Azure Monitor" + }, + { + "name": "VAR_COMPONENT", + "type": "constant", + "label": "component", + "value": "^(aio-akri-agent|akri-).*", + "description": "" + }, + { + "name": "VAR_COMPONENT_TEXT", + "type": "constant", + "label": "component_text", + "value": "AKRI", + "description": "" + }, + { + "name": "VAR_MYPREFIX_LATENCY_THRESHOLD_MS", + "type": "constant", + "label": "myprefix_latency_threshold_ms", + "value": "5000", + "description": "" + }, + { + "name": "VAR_LATENCY_PERCENTILE", + "type": "constant", + "label": "latency_percentile", + "value": "0.95", + "description": "" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "grafana-azure-monitor-datasource", + "name": "Azure Monitor", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "heatmap", + "name": "Heatmap", + "version": "" + }, + { + "type": "panel", + "id": "piechart", + "name": "Pie chart", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "state-timeline", + "name": "State timeline", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 8, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n Azure Edge Services - ${component_text} Health\n
\n
\n   Scenario Health (SLO/RUM) related to ${component_text}\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 10, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Service Health (Synthetics/Self-test)\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 60, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for ${component_text} ${__field.labels._}", + "url": "${__field.labels.url}?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#7f7f7f", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + }, + { + "color": "#7f7f7f", + "value": 404 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "^Self-test.*[^)]$" + }, + "properties": [ + { + "id": "links" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".* Overall Health$" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 1 + }, + { + "id": "links" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 5 + }, + "id": 16, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.72, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#label_replace(min(\r\n# label_replace(#label_replace(\r\n# (min(\r\n# aio_akri_instance_count{cluster=~\"$cluster\"} or\r\n# vector(0)>0\r\n# vector(0)>0\r\n# ) or vector(404))\r\n# ,\"_\",\"Akri Instance Count\",\"\",\"\") or\r\n# vector(0)>0\r\n#),\"_\",\"$component_text Overall Health\",\"\",\"\")\r\n\r\n\r\n## Akri Readiness health\r\n############################\r\nlabel_replace(min(\r\navg(label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n label_replace(label_join(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"^aio-akri-agent.*\"} or\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"^aio-akri-agent.*\"} or\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"^aio-akri-agent.*\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n /\r\n label_replace(label_join(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"^aio-akri-agent.*\"} or\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"^aio-akri-agent.*\"} or\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"^aio-akri-agent.*\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n) by (workload) >=0 \r\n) or vector(-1),\"_\",\"Akri Overall Health\",\"\",\"\")", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#label_replace(min(\r\n label_replace( \r\n #TODO: REPLACE BELOW WITH ALL OF THE INDIVIDUAL HEALTH-TEST SIGNALS THAT MAKE UP OVERALL SIGNAL, THEN COPY AND PASTE INTO QUERY A\r\n (min(\r\n 1 * sgn(\r\n 100*sum(rate(e4i_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\",e4i_mqtt_publish_result=\"Success\"}[$__rate_interval]))\r\n / sum(rate(e4i_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\"}[$__rate_interval]))\r\n > 99) or\r\n 0 * sgn(sum(rate(e4i_mqtt_message_publishing_duration_count{cluster=\"$cluster\",service_name=\"supervisor\"}[$__rate_interval])) > 0) or\r\n vector(0)>0\r\n ) or vector(-1))\r\n #,\"url\",\"/d/f46e5384-d78d-480a-911c-0328cb20b224/e4k-ping\",\"\",\"\") # UPDATE AND ENABLE WITH LABEL_REPLACE TO HAVE INLINE DATA LINK\r\n ,\"_\",\"Self-test Success Rate\",\"\",\"\") or\r\n label_replace(\r\n (min(\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n e4i_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n ))) < $myprefix_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n e4i_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n ))) >= $myprefix_latency_threshold_ms) or\r\n vector(0)>0\r\n ) or vector(404))\r\n #,\"url\",\"/d/f5a5c523-2cb6-42d8-b23f-06b0227fe40b/e4k-connect\",\"\",\"\")# UPDATE AND ENABLE WITH LABEL_REPLACE TO HAVE INLINE DATA LINK\r\n ,\"_\",\"Self-test latency\",\"\",\"\") or \r\n vector(0)>0\r\n#),\"_\",\"$component_text Overall Health\",\"\",\"\")", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "B" + } + ], + "title": "Service Health - TODO UPDATE ME", + "transformations": [], + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Click for Bluefin details", + "url": "/d/e57b7777-71be-43a8-87bd-d917391b154f/bluefin-overview?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 0.8 + }, + { + "color": "dark-green", + "value": 1 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Supervisor errors" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "line" + }, + { + "id": "custom.lineWidth", + "value": 3 + }, + { + "id": "custom.fillOpacity", + "value": 5 + }, + { + "id": "custom.pointSize", + "value": 5 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 0, + 5 + ], + "fill": "dot" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisLabel", + "value": "Error counts" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Supervisor Success Rate" + }, + "properties": [ + { + "id": "custom.axisSoftMax" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "0": { + "color": "#808080", + "index": 0 + } + }, + "type": "value" + } + ] + }, + { + "id": "max", + "value": 101 + }, + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 5 + }, + "id": 28, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "asc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(# BELOW IS AN EXAMPLE; REPLACE WITH WHATEVER PROVIDES DETAILS BEHIND HEALTH SIGNAL\r\n 100*sum(rate(e4i_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\",e4i_mqtt_publish_result=\"Success\"}[$__rate_interval]))\r\n / sum(rate(e4i_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\"}[$__rate_interval]))\r\n ,\"_\",\"Supervisor Success Rate\",\"\",\"\") or\r\nlabel_replace(\r\n 60*sum(rate(e4i_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\",e4i_mqtt_publish_result!=\"Success\"}[$__rate_interval]))\r\n# #0 * sgn(\r\n# round(sum(increase(stage_errors{cluster=~\"$cluster\",cloud_resource_id=~\"$bf_pipeline4selftest\"}[$__rate_interval])))#) or\r\n# #or vector(3)\r\n ,\"_\",\"Supervisor errors\",\"\",\"\") or\r\n vector(0)>0", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Self-test Output and Errors - TODO UPDATE ME", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Click for Bluefin details", + "url": "/d/e57b7777-71be-43a8-87bd-d917391b154f/bluefin-overview?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "hidden-timeline" + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Self-test latency threshold" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Self-test pipeline latency over threshold" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.lineWidth", + "value": 3 + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 9 + }, + "id": 29, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace( # BELOW IS AN EXAMPLE; REPLACE WITH WHATEVER PROVIDES DETAILS BEHIND HEALTH SIGNAL\r\n max(histogram_quantile(0.95, rate(\r\n e4i_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n ))) \r\n ,\"_\",\"Self-test pipeline latency\",\"\",\"\") or\r\nlabel_replace($myprefix_latency_threshold_ms * sgn(\r\n max(histogram_quantile(0.95, rate(\r\n e4i_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n )))\r\n ),\"_\",\"Self-test latency threshold\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n max(histogram_quantile(0.95, rate(\r\n e4i_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n ))) >= $myprefix_latency_threshold_ms\r\n ,\"x\",\"Over threshold\",\"\",\"\")\r\n ,\"_\",\"Self-test pipeline latency over threshold\",\"\",\"\") or\r\nlabel_replace(vector(0),\"_\",\"hidden-timeline\",\"\",\"\") or\r\nvector(0)>0", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + } + ], + "title": "Self-test Latency - TODO UPDATE ME", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 12, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Golden Metrics\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [ + { + "options": { + "match": "null+nan", + "result": { + "color": "transparent", + "index": 0 + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".*s$" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisLabel", + "value": "total count" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*[/]sec[)]$" + }, + "properties": [ + { + "id": "custom.axisLabel", + "value": "throughput (msgs/sec)" + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 15 + }, + "id": 50, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(avg(aio_akri_instance_count{cluster=\"$cluster\"}),\"_\",\"Akri Instance Count (e.g. opcua assets)\",\"\",\"\")", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Discovered Assets Count", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Success Rate" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 4 + }, + { + "id": "custom.axisSoftMin", + "value": 0 + }, + { + "id": "custom.axisSoftMax", + "value": 101 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*(Errors)$" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "unit", + "value": "none" + }, + { + "id": "custom.axisLabel", + "value": "Error Count" + }, + { + "id": "custom.drawStyle", + "value": "bars" + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "custom.axisSoftMin", + "value": 0 + }, + { + "id": "custom.axisSoftMax", + "value": 20 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 15 + }, + "id": 51, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(aio_akri_discovery_response_result{cluster=\"$cluster\", result=\"success\"}) / \r\n sum(aio_akri_discovery_response_result{cluster=\"$cluster\"})\r\n ,\"_\",\"Success Rate\",\"\",\"\") * 100 or\r\nvector(0) > 0", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Successful Discovery Rate", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 7, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "Self-test.*" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 0, + 10 + ], + "fill": "dot" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 15 + }, + "id": 52, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(avg(aio_akri_discovery_response_time_sum{cluster=\"$cluster\"}/aio_akri_discovery_response_time_count{cluster=\"$cluster\"})\r\n ,\"_\",\"Average Latency\",\"\",\"\")", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(histogram_quantile(0.95, rate(pipeline_latency_bucket{cluster=~\"$cluster\",cloud_resource_id=~\".*self-test-bluefin-pipeline.*\"}[$__rate_interval])),\"_\",\"P95\",\"\",\"\") or\r\nvector(0)>0", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "Latency", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 11, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Infrastructure Workload Health\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "Click for more details", + "url": "/d/eef9bf1c-b27a-4e86-a7f0-2a39cdfbeeca/health-infrastructure?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 25 + }, + "id": 31, + "links": [ + { + "targetBlank": true, + "title": "See infra workload health for all components", + "url": "/d/E5cCeHj4z/health-infra-workload?${cluster:queryparam}&${__url_time_range}" + } + ], + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.9, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Workload Readiness health\r\n############################\r\nlabel_replace(min(\r\navg(label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n label_replace(label_join(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n / label_replace(label_join(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n) by (workload) >=0 \r\n) or vector(0),\"_\",\"Workload Readiness\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Restart Health:\r\n############################\r\nlabel_replace(\r\n sgn(sum_over_time(sum(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[10m:1m]\r\n )*60)[1h:]) > 5) * 0.0 # RED: Cumulative restarts over X(5) time greater than Y(1h)\r\n or (max(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[5m:1m]\r\n )*60*5) > 0) * 0.5 # YELLOW: restarts detected but below Red threshold\r\n or sgn(max(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}\r\n + 1 >= 0))\r\n #or vector(1) # Healthy\r\n ,\"_\",\"Container Restart Health\",\"\",\"\")\r\n## uncomment below to t-shoot this health metric\r\n# or label_replace(sum_over_time(sum(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[10m:1m])*60)[1h:]),\"_\",\"Total-restarts-over-time\",\"\",\"\")\r\n# or label_replace((max(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[5m:1m])*60*5) without (__name__,uid,instance,job) > 0),\"_\",\"restart\",\"\",\"\") # Base query for counting restarts\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container CPU top-level health\r\n################################\r\nlabel_replace(\r\nmin(sgn( # Check for throttling > N indicating container is exceeding its CPU limits\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m]) \r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m])\r\n >= 0.60) # If throttle create is greater than this percentage, we'll multiply sgn by 0.5 to show as error (or warning depending on threshold coloring)\r\n ) # by (namespace,container) # These are commented out for top-level\r\n * 0.0\r\nor\r\nmin(sgn( # Check for throttling > N indicating container is exceeding its CPU limits\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m]) \r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m])\r\n >= 0.40) # If throttle create is greater than this percentage, we'll multiply sgn by 0.5 to show as error (or warning depending on threshold coloring)\r\n ) # by (namespace,container) # These are commented out for top-level\r\n * 0.5\r\nor\r\nmin( # Check to see if container is missing CPU Limits configuration\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"cpu\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n ) #by (namespace,container) # These are commented out for top-level\r\n,\"_\",\"Container CPU Health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Memory Health:\r\n###########################\r\nlabel_replace(\r\nmin( # Look for high memory utilization\r\n sgn((\r\n max(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container)\r\n / min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"memory\",pod=~\"${component:raw}\"}) by (namespace, container)\r\n ) >= .95) - 0.5 # show health state of 0.5 if container memory utilization >= 95%\r\n) #by (container) \r\nor\r\nmin( # Look for missing limits which we will show as 0 if missing\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"memory\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n) #by (container) \r\n,\"_\",\"Container Memory health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Health Summary", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "max(rate(container_cpu_usage_seconds_total{namespace=~\"alice-springs|symphony-k8s-system\",container=\"\",cpu=\"total\"}[5m])*300 > 0) ": "POD CPU (max)", + "min( # Workload ready percents (for deployment, daemonset, replicaset, and statefulset)\r\n label_replace(label_join(\r\n {job=\"kube-state-metrics\",namespace=~\"alice-springs|symphony-k8s-system\",\r\n __name__=~\"kube_(deployment|daemonset|replicaset|statefulset)_status_(replicas_ready|ready_replicas|number_ready)\"}\r\n ,\"workload\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n / label_replace(label_join(\r\n {job=\"kube-state-metrics\",namespace=~\"alice-springs|symphony-k8s-system\",\r\n __name__=~\"kube_(deployment|daemonset|replicaset|statefulset)_status_(replicas|desired_number_scheduled)\"}\r\n ,\"workload\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n) #by (workloadType) #namespace) #, workloadType) #, workload)": "Workload ready health" + } + } + } + ], + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 20 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 6, + "y": 25 + }, + "id": 33, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(sum ( # by(workloadType) (\r\n#min(\r\n# label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n label_replace(label_join(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n),\"_\",\"Ready\",\"\",\"\")\r\n# / label_replace(label_join(\r\n# kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\"$namespace\",daemonset=~\"${component:raw}\"} or\r\n# kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\"$namespace\",deployment=~\"${component:raw}\"} or\r\n# kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\"$namespace\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n# ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n#) by (workload) >=0 ", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#min(\r\n# label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n# label_replace(label_join(\r\n# kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",deployment=~\"${component:raw}\"} or\r\n# kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",daemonset=~\"${component:raw}\"} or\r\n# kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n# / label_replace(label_join(\r\n label_replace(sum(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n ),\"_\",\"Requested\",\"\",\"\")\r\n# ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n#) by (workload) >=0 ", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Workloads", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 8, + "y": 25 + }, + "id": 35, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor label_replace(vector(0),\"status\",\"Ready\",\"\",\"\")\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "DaemonSets", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 10, + "y": 25 + }, + "id": 37, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor label_replace(vector(0),\"status\",\"Ready\",\"\",\"\") # this is to zero if no workloads of this type exist\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "Deployments", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 12, + "y": 25 + }, + "id": 39, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor \r\nlabel_replace(vector(0),\"status\",\"Ready\",\"\",\"\")\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "StatefulSets", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 1 + }, + { + "color": "dark-orange", + "value": 5 + }, + { + "color": "red", + "value": 10 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 14, + "y": 25 + }, + "id": 41, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Container Restarts\r\nlabel_replace(ceil(sum_over_time(sum(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[10m:1m])*60)[1h:])),\"_\",\"restarts\",\"\",\"\")\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 40 + }, + { + "color": "red", + "value": 60 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percent containers with CPU Limits (%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "super-light-purple", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Usage (milli-cores)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisColorMode", + "value": "series" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Max Throttled (%)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "thresholds", + "seriesBy": "max" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 25 + }, + "id": 59, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\n(label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))*1000,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\") )\r\n# Percent of containers with limits defined\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"Percent containers with CPU Limits (%)\",\"\",\"\")\r\n# CPU Throttling:\r\nor label_replace(100*(max(\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n )),\"_\",\"CPU Max Throttled (%)\",\"\",\"\")\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(quantile_over_time(0.95,sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\nvector(0)>0\r\n# Sum of all limits defined, in Cores\r\nor label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# WIP:\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"WIP-PERCENT_WITH_LIMITS\",\"\",\"\")\r\nor label_replace(count(\r\n kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"})\r\n ,\"_\",\"WIP-NUMERATOR\",\"\",\"\")\r\nor label_replace(count(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) #without(cluster,container,cpu,id,image,instance,job,name,namespace,pod)\r\n ,\"_\",\"WIP-DENOMINATOR\",\"\",\"\")\r\n# ", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "CPU", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 80 + }, + { + "color": "orange", + "value": 85 + }, + { + "color": "red", + "value": 90 + }, + { + "color": "dark-red", + "value": 95 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percent containers with Memory Limits (%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mem Working Bytes (MB)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisColorMode", + "value": "series" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mem Max Usage vs Limit (%)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "thresholds", + "seriesBy": "max" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 25 + }, + "id": 61, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory Usage (MB version)\r\n(label_replace(sum(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"Mem Working Bytes (MB)\",\"\",\"\") )\r\n# Percent containers with limits\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"memory\"}) /\r\n count(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}) *100\r\n ,\"_\",\"Percent containers with Memory Limits (%)\",\"\",\"\")\r\n# Max Mem % Usage:\r\nor label_replace(100*(max(\r\n max_over_time((max by(container)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}))[10m:])\r\n / max by(container)(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"memory\"})\r\n )),\"_\",\"Mem Max Usage vs Limit (%)\",\"\",\"\")\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(quantile_over_time(0.95,sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\nvector(0)>0\r\n# Sum of all limits defined, in Cores\r\nor label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# WIP:\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"WIP-PERCENT_WITH_LIMITS\",\"\",\"\")\r\nor label_replace(count(\r\n kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"})\r\n ,\"_\",\"WIP-NUMERATOR\",\"\",\"\")\r\nor label_replace(count(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) #without(cluster,container,cpu,id,image,instance,job,name,namespace,pod)\r\n ,\"_\",\"WIP-DENOMINATOR\",\"\",\"\")\r\n# ", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "milli-cores", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels._}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels._}.*" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Overall" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "number" + }, + "properties": [ + { + "id": "links" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 29 + }, + "id": 47, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(_)(\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum by(pod)(rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") or\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum (rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\".Overall\",\"\",\"\") or\r\nvector(0)>0)", + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + } + ], + "title": "CPU Usage by Workload", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "working bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels._}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels._}.*" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byType", + "options": "number" + }, + "properties": [ + { + "id": "links" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 29 + }, + "id": 48, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(_)(\r\nlabel_replace(\r\n sum by(pod)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") \r\n)\r\n##(label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))*1000,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\") )\r\n## and label_replace(max_over_time(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))[3d:]) < 0.2,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\")) # Show milli-cores if rate below 0.2 cores\r\n# CPU Time (cores version, if >= 0.2 cores)\r\n##or (label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval])),\"_\",\"CPU Usage (cores)\",\"\",\"\") \r\n## and label_replace(max_over_time(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))[3d:]) >= 0.2,\"_\",\"CPU Usage (cores)\",\"\",\"\")) # Show in cores if rate at or above 0.2 cores\r\n# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(max_over_time(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\n# Sum of all limits defined, in Cores\r\n##or label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# CPU Throttling:\r\n##or label_replace(100*(max(\r\n## rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n## / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n## )),\"_\",\"CPU Max Throttled (%)\",\"\",\"\")\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Memory Usage by Workload", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Click on data series to drill down into pod details", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "milli-cores", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels.pod}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels.pod}" + } + ], + "mappings": [ + { + "options": { + "match": "null+nan", + "result": { + "color": "transparent", + "index": 0 + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Overall" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 37 + }, + "id": 56, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(pod)(\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum by(pod)(rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\"$1\",\"pod\",\"(.*)\") or #,\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") or\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum (rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"pod\",\".Overall\",\"\",\"\") or\r\nvector(0)>0)", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(_)(\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum by(pod)(rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") or\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum (rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\".Overall\",\"\",\"\") or\r\nvector(0)>0)", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "CPU Usage by Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Click on data series to drill down into pod details", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "working bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels.pod}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels.pod}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 37 + }, + "id": 57, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory working bytes\r\nmax by(pod)(\r\nlabel_replace(\r\n sum by(pod)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") \r\n)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory working bytes\r\nmax by(_)(\r\nlabel_replace(\r\n sum by(pod)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") \r\n)", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Memory Usage by Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 45 + }, + "id": 13, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Errors & Logs\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "yellow", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PodName" + }, + "properties": [ + { + "id": "custom.width", + "value": 300 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Reason" + }, + "properties": [ + { + "id": "custom.width", + "value": 112 + }, + { + "id": "custom.align", + "value": "center" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "Failed": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ] + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Count" + }, + "properties": [ + { + "id": "custom.width", + "value": 114 + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "color", + "value": { + "mode": "continuous-BlPu" + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.width", + "value": 200 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Message" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 55, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "LastSeen" + } + ] + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "azureLogAnalytics": { + "query": "KubeEvents\r\n//| where TimeGenerated > ago(1d)\r\n| where ClusterName == '$cluster'\r\n| where Name matches regex '${component:raw}'\r\n//| order by TimeGenerated desc\r\n| order by LastSeen desc, FirstSeen desc, TimeGenerated desc\r\n| project-rename PodName = Name\r\n| project FirstSeen, LastSeen, Count, PodName, Reason, Message\r\n| take 10", + "resources": [ + "/subscriptions/af342bf1-1ace-41df-902c-47921400551b" + ], + "resultFormat": "table" + }, + "azureMonitor": { + "allowedTimeGrainsMs": [], + "timeGrain": "auto" + }, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "queryType": "Azure Log Analytics", + "refId": "A" + } + ], + "title": "Last 10 Kube Events entries (from $cluster)", + "type": "table" + }, + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "yellow", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PodName" + }, + "properties": [ + { + "id": "custom.width", + "value": 386 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.width", + "value": 200 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ContainerName" + }, + "properties": [ + { + "id": "custom.width", + "value": 302 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "LogMessage" + }, + "properties": [ + { + "id": "custom.width", + "value": 1656 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "LogSource" + }, + "properties": [ + { + "id": "custom.width", + "value": 140 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 15, + "w": 24, + "x": 0, + "y": 55 + }, + "id": 64, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "azureLogAnalytics": { + "query": "ContainerLogV2\r\n| where TimeGenerated >= $__timeFrom() and TimeGenerated <= $__timeTo()\r\n| where _ResourceId contains '$cluster'\r\n| where ContainerName matches regex '${component:raw}'\r\n| where LogSource == 'stderr'\r\n| order by TimeGenerated desc\r\n| project TimeGenerated, PodName, ContainerName, LogSource, LogMessage\r\n| take 100", + "resources": [ + "/subscriptions/af342bf1-1ace-41df-902c-47921400551b" + ], + "resultFormat": "table" + }, + "azureMonitor": { + "allowedTimeGrainsMs": [], + "timeGrain": "auto" + }, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "queryType": "Azure Log Analytics", + "refId": "A" + } + ], + "title": "Error Logs - Last 100 Container Logs entries from STDERR (cluster: $cluster)", + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 70 + }, + "id": 14, + "links": [ + { + "targetBlank": true, + "title": "Open ${component_text} - Overview page", + "url": "/d/e57b7777-71be-43a8-87bd-d917391b154f/bluefin-overview?${__all_variables}&${__url_time_range}" + } + ], + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   ${component_text}-specific\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "The akri_instance_count metric", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 3, + "x": 0, + "y": 72 + }, + "id": 62, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "aio_akri_instance_count{cluster=~\"$cluster\"}", + "format": "table", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Akri Instance Count", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "The aio_akri_discovery_response_time metric", + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 3, + "y": 72 + }, + "id": 67, + "options": { + "calculate": false, + "cellGap": 1, + "color": { + "exponent": 0.5, + "fill": "dark-orange", + "mode": "scheme", + "reverse": false, + "scale": "exponential", + "scheme": "Oranges", + "steps": 64 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": true + }, + "rowsFrame": { + "layout": "auto" + }, + "tooltip": { + "show": true, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false + } + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(increase(aio_akri_discovery_response_time_bucket{cluster=\"$cluster\"}[10m])) by (le)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Akri Discovery Response Time", + "type": "heatmap" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Discovery Fail Count" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Discovery Success Count" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 13, + "x": 11, + "y": 72 + }, + "id": 69, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(aio_akri_discovery_response_result{cluster=\"$cluster\", result=\"success\"})\r\n ,\"_\",\"Discovery Success Count\",\"\",\"\") or\r\nlabel_replace(\r\n sum(aio_akri_discovery_response_result{cluster=\"$cluster\", result=\"fail\"})\r\n ,\"_\",\"Discovery Fail Count\",\"\",\"\") or\r\nvector(0) > 0", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Discovery Results", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 7, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "Self-test.*" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 0, + 10 + ], + "fill": "dot" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 80 + }, + "id": 70, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace((aio_akri_discovery_response_time_sum{cluster=\"$cluster\"}/aio_akri_discovery_response_time_count{cluster=\"$cluster\"})\r\n ,\"_\",\"Average Latency\",\"\",\"\")", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(histogram_quantile(0.95, rate(pipeline_latency_bucket{cluster=~\"$cluster\",cloud_resource_id=~\".*self-test-bluefin-pipeline.*\"}[$__rate_interval])),\"_\",\"P95\",\"\",\"\") or\r\nvector(0)>0", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "Individual Node Latency", + "type": "timeseries" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "description": "Defines the service Component this report focuses on.", + "hide": 2, + "name": "component", + "query": "${VAR_COMPONENT}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_COMPONENT}", + "text": "${VAR_COMPONENT}", + "selected": false + }, + "options": [ + { + "value": "${VAR_COMPONENT}", + "text": "${VAR_COMPONENT}", + "selected": false + } + ] + }, + { + "description": "Defines the service Component this report focuses on.", + "hide": 2, + "name": "component_text", + "query": "${VAR_COMPONENT_TEXT}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_COMPONENT_TEXT}", + "text": "${VAR_COMPONENT_TEXT}", + "selected": false + }, + "options": [ + { + "value": "${VAR_COMPONENT_TEXT}", + "text": "${VAR_COMPONENT_TEXT}", + "selected": false + } + ] + }, + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_node_status_condition", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "kube_node_status_condition", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*cluster=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "hide": 2, + "includeAll": true, + "multi": true, + "name": "namespace", + "options": [], + "query": { + "query": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "description": "Latency threshold for health signal", + "hide": 2, + "label": "", + "name": "myprefix_latency_threshold_ms", + "query": "${VAR_MYPREFIX_LATENCY_THRESHOLD_MS}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_MYPREFIX_LATENCY_THRESHOLD_MS}", + "text": "${VAR_MYPREFIX_LATENCY_THRESHOLD_MS}", + "selected": false + }, + "options": [ + { + "value": "${VAR_MYPREFIX_LATENCY_THRESHOLD_MS}", + "text": "${VAR_MYPREFIX_LATENCY_THRESHOLD_MS}", + "selected": false + } + ] + }, + { + "hide": 2, + "name": "latency_percentile", + "query": "${VAR_LATENCY_PERCENTILE}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_LATENCY_PERCENTILE}", + "text": "${VAR_LATENCY_PERCENTILE}", + "selected": false + }, + "options": [ + { + "value": "${VAR_LATENCY_PERCENTILE}", + "text": "${VAR_LATENCY_PERCENTILE}", + "selected": false + } + ] + }, + { + "auto": true, + "auto_count": 300, + "auto_min": "5m", + "current": { + "selected": false, + "text": "auto", + "value": "$__auto_interval_latency_quantile_range" + }, + "hide": 2, + "name": "latency_quantile_range", + "options": [ + { + "selected": true, + "text": "auto", + "value": "$__auto_interval_latency_quantile_range" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "15m", + "value": "15m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "3h", + "value": "3h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "24h", + "value": "24h" + } + ], + "query": "5m,10m,15m,1h,3h,6h,24h", + "queryValue": "", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "aio-health-service-akri", + "uid": "df11b4b1-2dcb-4e6b-af47-4c9fc5793f56", + "version": 24, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-health-service-dp-1698853592723.json b/samples/dashboard/grafana-dashboards/aio-health-service-dp-1698853592723.json new file mode 100644 index 0000000..55167f0 --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-health-service-dp-1698853592723.json @@ -0,0 +1,4792 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + }, + { + "name": "DS_AZURE_MONITOR", + "label": "Azure Monitor", + "description": "", + "type": "datasource", + "pluginId": "grafana-azure-monitor-datasource", + "pluginName": "Azure Monitor" + }, + { + "name": "VAR_COMPONENT", + "type": "constant", + "label": "component", + "value": "^(bf-|bluefin-|aio-dp-|dp-).*", + "description": "" + }, + { + "name": "VAR_COMPONENT_TEXT", + "type": "constant", + "label": "component_text", + "value": "Data Processor", + "description": "" + }, + { + "name": "VAR_AIO_DP_SELF_TEST_PIPELINE", + "type": "constant", + "label": "aio_dp_self_test_pipeline", + "value": ".*self-test.*", + "description": "" + }, + { + "name": "VAR_LATENCY_PERCENTILE", + "type": "constant", + "label": "latency_percentile", + "value": "0.95", + "description": "" + }, + { + "name": "VAR_AIO_DP_ERROR_THRESHOLD", + "type": "constant", + "label": "aio_dp_error_threshold", + "value": "20", + "description": "" + }, + { + "name": "VAR_AIO_DP_NATS_UTILIZATION_THRESHOLD", + "type": "constant", + "label": "aio_dp_nats_utilization_threshold", + "value": "0.90", + "description": "" + }, + { + "name": "VAR_AIO_DP_LATENCY_THRESHOLD_MS", + "type": "constant", + "label": "aio_dp_latency_threshold_ms", + "value": "1000", + "description": "" + }, + { + "name": "VAR_AIO_DP_ERROR_RATE", + "type": "constant", + "label": "aio_dp_error_rate", + "value": "0.05", + "description": "" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "grafana-azure-monitor-datasource", + "name": "Azure Monitor", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "piechart", + "name": "Pie chart", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "state-timeline", + "name": "State timeline", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 8, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n Azure Edge Services - ${component_text} Health\n
\n
\n   Stage Count and Reference Data\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 11, + "x": 0, + "y": 3 + }, + "id": 71, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "count(aio_dp_stage_info{cluster=\"$cluster\"}) by (stage_type) ", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Stage counts", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Enrichment latency broken down by pipeline, over interval", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "refdata-enrich" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 11, + "y": 3 + }, + "id": 75, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(rate(aio_dp_enrich_latency_bucket{cluster=\"$cluster\"}[$__rate_interval])) by (pipeline_id)", + "interval": "", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "RefData Enrichment Latency", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Total count of enriched messages across the cluster\n\nTODO: Make count / interval (tbd)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 19, + "y": 3 + }, + "id": 73, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(aio_dp_enrich_latency_count{cluster=\"$cluster\"})", + "instant": false, + "interval": "", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Enriched Message Count", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Unique refdata stores\n\nTodo: get dataset names", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 19, + "y": 7 + }, + "id": 74, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count(count by(enrich_datasetid, cluster) (aio_dp_refdata_global_store_get_latency_count{cluster=\"$cluster\"}))", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Refdata Store Count", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 76, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Scenario Health (SLO/RUM) related to ${component_text}\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 60, + "lineWidth": 0, + "spanNulls": false + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "green", + "value": 1 + }, + { + "color": "text", + "value": 404 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "NATS Utilization" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Click for details on ${__field.labels._}", + "url": "/d/e17d0b7f-9771-4cb8-adf9-56cbaef3fff6/aio-service-dp-messagestore?${__all_variables}&${__url_time_range}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Pipeline Latency" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Click for details on ${__field.labels._}", + "url": "/d/4f637c27-a19f-489e-a4af-719f1baa0a19/aio-service-dp-pipeline?${__all_variables}&${__url_time_range}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Errors" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Click for details on Stage ${__field.labels._}", + "url": "/d/e6d7cca2-c5a9-4917-bf3b-43634132f009/aio-service-dp-stage?${__all_variables}&${__url_time_range}" + }, + { + "targetBlank": true, + "title": "Click for details on Pipeline ${__field.labels._}", + "url": "/d/4f637c27-a19f-489e-a4af-719f1baa0a19/aio-service-dp-pipeline?${__all_variables}&${__url_time_range}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Heartbeats" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Click for details on ${__field.labels._}", + "url": "/d/7fd56ac4-71cc-419c-9001-bc148b45a98c/aio-service-dp-overview?${__all_variables}&${__url_time_range}" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 0, + "y": 13 + }, + "id": 64, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.72, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(min(\r\n label_replace(\r\n (\r\n 1 - min(\r\n sgn(sum(rate(aio_dp_stage_errors{cluster=~\"$cluster\"}[$__rate_interval])) <= $aio_dp_error_threshold)\r\n or\r\n sgn(sum(rate(aio_dp_reader_errors{cluster=~\"$cluster\"}[$__rate_interval])) <= $aio_dp_error_threshold)\r\n )\r\n or vector(1)\r\n )\r\n ,\"_\",\"Errors\",\"\",\"\") \r\n or\r\n label_replace(\r\n (\r\n sgn(\r\n (\r\n sum(rate(aio_dp_reader_errors{cluster=\"$cluster\"}[$__rate_interval])) + \r\n sum(rate(aio_dp_stage_errors{cluster=\"$cluster\"}[$__rate_interval]))\r\n ) / \r\n (\r\n sum(rate(aio_dp_reader_incoming_messages{cluster=\"$cluster\"}[$__rate_interval])) + \r\n sum(rate(aio_dp_stage_incoming_messages{cluster=\"$cluster\"}[$__rate_interval]))\r\n ) < $aio_dp_error_rate\r\n )\r\n or vector(1)\r\n )\r\n ,\"_\",\"Success Rate\",\"\",\"\")\r\n or\r\n label_replace(\r\n (min(\r\n sgn(\r\n max(\r\n histogram_quantile(0.95, rate(aio_dp_pipeline_latency_bucket{cluster=~\"$cluster\"}[$__rate_interval]))\r\n ) < $aio_dp_latency_threshold_ms\r\n )\r\n or\r\n 1 - sgn(\r\n max(\r\n histogram_quantile(0.95, rate(aio_dp_pipeline_latency_bucket{cluster=~\"$cluster\"}[$__rate_interval]))\r\n ) >= $aio_dp_latency_threshold_ms\r\n )\r\n ) \r\n or vector(404))\r\n ,\"_\",\"Pipeline Latency\",\"\",\"\")\r\n or \r\n label_replace(\r\n (\r\n min(\r\n sgn(\r\n sum(rate(aio_dp_reader_processed_heartbeats{cluster=~\"$cluster\"}[$__rate_interval]))\r\n >= sum(rate(aio_dp_reader_incoming_heartbeats{cluster=~\"$cluster\"}[$__rate_interval]))\r\n )\r\n or\r\n sgn(\r\n sum(rate(aio_dp_stage_heartbeats{cluster=~\"$cluster\"}[$__rate_interval]))\r\n >= sum(rate(aio_dp_reader_processed_heartbeats{cluster=~\"$cluster\"}[$__rate_interval]))\r\n )\r\n )\r\n or vector(404))\r\n ,\"_\",\"Heartbeats\",\"\",\"\")\r\n or\r\n label_replace(\r\n (\r\n sgn(\r\n sum by(server_id)(nats_varz_jetstream_stats_storage{cluster=~\"$cluster\"}) > 0\r\n and\r\n (sum by(server_id)(nats_varz_jetstream_stats_storage{cluster=~\"$cluster\"}) / \r\n sum by(server_id)(nats_varz_jetstream_config_max_storage{cluster=~\"$cluster\"}))\r\n <= $aio_dp_nats_utilization_threshold\r\n )\r\n or vector(404))\r\n ,\"_\",\"Message Store\",\"\",\"\")\r\n),\"_\",\"SLO Health\",\"\",\"\")", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#label_replace(min(\r\n label_replace(\r\n (\r\n 1 - min(\r\n sgn(sum(rate(aio_dp_stage_errors{cluster=~\"$cluster\"}[$__rate_interval])) <= $aio_dp_error_threshold)\r\n or\r\n sgn(sum(rate(aio_dp_reader_errors{cluster=~\"$cluster\"}[$__rate_interval])) <= $aio_dp_error_threshold)\r\n )\r\n or vector(1)\r\n )\r\n ,\"_\",\"Errors\",\"\",\"\") \r\n or\r\n label_replace(\r\n (\r\n sgn(\r\n (\r\n sum(rate(aio_dp_reader_errors{cluster=\"$cluster\"}[$__rate_interval])) + \r\n sum(rate(aio_dp_stage_errors{cluster=\"$cluster\"}[$__rate_interval]))\r\n ) / \r\n (\r\n sum(rate(aio_dp_reader_incoming_messages{cluster=\"$cluster\"}[$__rate_interval])) + \r\n sum(rate(aio_dp_stage_incoming_messages{cluster=\"$cluster\"}[$__rate_interval]))\r\n ) < $aio_dp_error_rate\r\n )\r\n or vector(1)\r\n )\r\n ,\"_\",\"Success Rate\",\"\",\"\")\r\n or\r\n label_replace(\r\n (min(\r\n sgn(\r\n max(\r\n histogram_quantile(0.95, rate(aio_dp_pipeline_latency_bucket{cluster=~\"$cluster\"}[$__rate_interval]))\r\n ) < $aio_dp_latency_threshold_ms\r\n )\r\n or\r\n 1 - sgn(\r\n max(\r\n histogram_quantile(0.95, rate(aio_dp_pipeline_latency_bucket{cluster=~\"$cluster\"}[$__rate_interval]))\r\n ) >= $aio_dp_latency_threshold_ms\r\n )\r\n ) \r\n or vector(404))\r\n ,\"_\",\"Pipeline Latency\",\"\",\"\")\r\n or \r\n label_replace(\r\n (\r\n min(\r\n sgn(\r\n sum(rate(aio_dp_reader_processed_heartbeats{cluster=~\"$cluster\"}[$__rate_interval]))\r\n >= sum(rate(aio_dp_reader_incoming_heartbeats{cluster=~\"$cluster\"}[$__rate_interval]))\r\n )\r\n or\r\n sgn(\r\n sum(rate(aio_dp_stage_heartbeats{cluster=~\"$cluster\"}[$__rate_interval]))\r\n >= sum(rate(aio_dp_reader_processed_heartbeats{cluster=~\"$cluster\"}[$__rate_interval]))\r\n )\r\n )\r\n or vector(404))\r\n ,\"_\",\"Heartbeats\",\"\",\"\")\r\n or\r\n label_replace(\r\n (\r\n sgn(\r\n sum by(server_id)(nats_varz_jetstream_stats_storage{cluster=~\"$cluster\"}) > 0\r\n and\r\n (sum by(server_id)(nats_varz_jetstream_stats_storage{cluster=~\"$cluster\"}) / \r\n sum by(server_id)(nats_varz_jetstream_config_max_storage{cluster=~\"$cluster\"}))\r\n <= $aio_dp_nats_utilization_threshold\r\n )\r\n or vector(404))\r\n ,\"_\",\"Message Store\",\"\",\"\")\r\n#),\"_\",\"SLO Health\",\"\",\"\")", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "B" + } + ], + "title": "SLOs", + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Click for Data Processor details", + "url": "/d/e57b7777-71be-43a8-87bd-d917391b154f/aio-service-dp-overview?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 13 + }, + "id": 66, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "avg_over_time(histogram_quantile(0.95, sum(rate(aio_dp_pipeline_internal_latency_bucket{cluster=\"$cluster\"}[$__rate_interval])) by (le, cloud_resource_id))[$__range:])", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + } + ], + "title": "Pipeline Internal Latency", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "orange", + "value": 90 + }, + { + "color": "red", + "value": 95 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Unhealthy" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 13 + }, + "id": 62, + "links": [ + { + "targetBlank": true, + "title": "Show details on Data Processor - Message Store dashboard", + "url": "/d/yQUo5l17k/aio-service-dp-messagestore?${__all_variables}&${__url_time_range}" + } + ], + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(max(100*\r\n sum by(server_id)(nats_varz_jetstream_stats_storage{cluster=~\"$cluster\"})\r\n / sum by(server_id)(nats_varz_jetstream_config_max_storage{cluster=~\"$cluster\"})\r\n ),\"_\",\"Max Utilization\",\"\",\"\")", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "NATS Message Store Utilization", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Click for Data Processor details", + "url": "/d/e57b7777-71be-43a8-87bd-d917391b154f/aio-service-dp-overview?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 0.8 + }, + { + "color": "dark-green", + "value": 1 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Self-test error rate" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "line" + }, + { + "id": "custom.lineWidth", + "value": 3 + }, + { + "id": "custom.fillOpacity", + "value": 5 + }, + { + "id": "custom.pointSize", + "value": 5 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 0, + 5 + ], + "fill": "dot" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Self-test output (msgs/min)" + }, + "properties": [ + { + "id": "custom.axisSoftMax", + "value": 3 + }, + { + "id": "mappings", + "value": [ + { + "options": { + "0": { + "color": "#808080", + "index": 0 + } + }, + "type": "value" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 17 + }, + "id": 65, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "asc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": " label_replace(\r\n max(round(rate(aio_dp_stage_incoming_messages{cluster=~\"$cluster\", stage_type=~\"output/.*\"}[$__rate_interval])*60))\r\n ,\"_\",\"Output (msgs/min)\",\"\",\"\")\r\n or\r\n label_replace(\r\n 0 < round(sum(increase(aio_dp_stage_errors{cluster=~\"$cluster\"}[$__rate_interval])) + sum(rate(aio_dp_reader_errors{cluster=\"$cluster\"}[$__rate_interval])))\r\n ,\"_\",\"Error rate\",\"\",\"\")\r\n or\r\n vector(0) > 0", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + } + ], + "title": "Output Messages and Errors", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "green", + "mode": "fixed" + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 21 + }, + "id": 67, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "count(count by (cloud_resource_id, cluster) (rate(aio_dp_pipeline_latency_bucket{cluster=\"$cluster\"}[$__rate_interval])))", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + } + ], + "title": "Number of Pipelines", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "green", + "mode": "fixed" + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 21 + }, + "id": 68, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_reader_incoming_messages{cluster=\"$cluster\"}[$__rate_interval]))", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + } + ], + "title": "Number of Incoming Messages", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 25 + }, + "id": 10, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Service Health (Synthetics/Self-test)\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 60, + "lineWidth": 0, + "spanNulls": false + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#7f7f7f", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + }, + { + "color": "#7f7f7f", + "value": 404 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Self-test input (MQ)" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Show details from the MQ Service Health dashboard", + "url": "/d/e2e98c97-7655-44d1-b8f3-5008b7f6ffbb/aio-health-service-mq?${__all_variables}&${__url_time_range}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Store Utilization" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Show details from the DP message store dashboard", + "url": "/d/e17d0b7f-9771-4cb8-adf9-56cbaef3fff6/aio-service-dp-messagestore?${__all_variables}&${__url_time_range}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Self-test stage errors" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Click for details on ${__field.labels._}", + "url": "/d/e6d7cca2-c5a9-4917-bf3b-43634132f009/aio-service-dp-stage?${__all_variables}&${__url_time_range}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Self-test pipeline latency" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Click for details on ${__field.labels._}", + "url": "/d/4f637c27-a19f-489e-a4af-719f1baa0a19/aio-service-dp-pipeline?${__all_variables}&${__url_time_range}" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 27 + }, + "id": 16, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.72, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(min(\r\n label_replace(label_replace(\r\n (min(\r\n label_replace(aio_mq_connect_route_replication_correctness{cluster=~\"$cluster\"},\"depHealth\",\"connect\",\"\",\"\") or\r\n label_replace(aio_mq_ping_correctness{cluster=~\"$cluster\"},\"depHealth\",\"ping\",\"\",\"\") or\r\n label_replace(aio_mq_publish_route_replication_correctness{cluster=~\"$cluster\"},\"depHealth\",\"publish\",\"\",\"\") or\r\n label_replace(aio_mq_subscribe_route_replication_correctness{cluster=~\"$cluster\"},\"depHealth\",\"subscribe\",\"\",\"\") or\r\n label_replace(aio_mq_unsubscribe_route_replication_correctness{cluster=~\"$cluster\"},\"depHealth\",\"unsubscribe\",\"\",\"\") or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"/d/e2e98c97-7655-44d1-b8f3-5008b7f6ffbb/aio-health-service-mq\",\"\",\"\")\r\n ,\"_\",\"Self-test input (MQ)\",\"\",\"\") or\r\n label_replace(\r\n (min(\r\n 0 * sgn(0 < round(sum(increase(aio_dp_stage_errors{cluster=~\"$cluster\",cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}[$__rate_interval])))) or\r\n 1 * sgn(aio_dp_stage_incoming_messages{cluster=~\"$cluster\", stage_type=~\"output/.*\", cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"Self-test stage errors\",\"\",\"\") or\r\n label_replace(\r\n (min(sgn(rate(\r\n aio_dp_stage_incoming_messages{cluster=~\"$cluster\", stage_type=~\"output/.*\", cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}[$__rate_interval]\r\n )*60)) or vector(-1))\r\n ,\"_\",\"Self-test output\",\"\",\"\") or\r\n label_replace(\r\n (min(\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_dp_pipeline_latency_bucket{cluster=~\"$cluster\",cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}[5m]\r\n ))) < $aio_dp_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_dp_pipeline_latency_bucket{cluster=~\"$cluster\",cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}[5m]\r\n ))) >= $aio_dp_latency_threshold_ms) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"Self-test pipeline latency\",\"\",\"\") or \r\n label_replace(label_replace(\r\n (min(\r\n 0 * sgn(max(\r\n 100 * sum by(server_id)(nats_varz_jetstream_stats_storage{cluster=~\"$cluster\"})\r\n / sum by(server_id)(nats_varz_jetstream_config_max_storage{cluster=~\"$cluster\"})\r\n ) > 90) or\r\n 1 * sgn(max(\r\n 100 * sum by(server_id)(nats_varz_jetstream_stats_storage{cluster=~\"$cluster\"})\r\n / sum by(server_id)(nats_varz_jetstream_config_max_storage{cluster=~\"$cluster\"})\r\n ) <= 90) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"/d/e17d0b7f-9771-4cb8-adf9-56cbaef3fff6/aio-service-dp-messagestore\",\"\",\"\")\r\n ,\"_\",\"Store Utilization\",\"\",\"\") or \r\n vector(0)>0\r\n),\"_\",\"Overall Health\",\"\",\"\")", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# label_replace(min(\r\n label_replace(label_replace(\r\n (min(\r\n label_replace(aio_mq_connect_route_replication_correctness{cluster=~\"$cluster\"},\"depHealth\",\"connect\",\"\",\"\") or\r\n label_replace(aio_mq_ping_correctness{cluster=~\"$cluster\"},\"depHealth\",\"ping\",\"\",\"\") or\r\n label_replace(aio_mq_publish_route_replication_correctness{cluster=~\"$cluster\"},\"depHealth\",\"publish\",\"\",\"\") or\r\n label_replace(aio_mq_subscribe_route_replication_correctness{cluster=~\"$cluster\"},\"depHealth\",\"subscribe\",\"\",\"\") or\r\n label_replace(aio_mq_unsubscribe_route_replication_correctness{cluster=~\"$cluster\"},\"depHealth\",\"unsubscribe\",\"\",\"\") or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"/d/e2e98c97-7655-44d1-b8f3-5008b7f6ffbb/aio-health-service-mq\",\"\",\"\")\r\n ,\"_\",\"Self-test input (MQ)\",\"\",\"\") or\r\n label_replace(\r\n (min(\r\n 0 * sgn(0 < round(sum(increase(aio_dp_stage_errors{cluster=~\"$cluster\",cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}[$__rate_interval])))) or\r\n 1 * sgn(aio_dp_stage_incoming_messages{cluster=~\"$cluster\", stage_type=~\"output/.*\", cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"Self-test stage errors\",\"\",\"\") or\r\n label_replace(\r\n (min(sgn(rate(\r\n aio_dp_stage_incoming_messages{cluster=~\"$cluster\", stage_type=~\"output/.*\", cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}[$__rate_interval]\r\n )*60)) or vector(-1))\r\n ,\"_\",\"Self-test output\",\"\",\"\") or\r\n label_replace(\r\n (min(\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_dp_pipeline_latency_bucket{cluster=~\"$cluster\",cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}[5m]\r\n ))) < $aio_dp_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_dp_pipeline_latency_bucket{cluster=~\"$cluster\",cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}[5m]\r\n ))) >= $aio_dp_latency_threshold_ms) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"Self-test pipeline latency\",\"\",\"\") or \r\n label_replace(label_replace(\r\n (min(\r\n 0 * sgn(max(\r\n 100 * sum by(server_id)(nats_varz_jetstream_stats_storage{cluster=~\"$cluster\"})\r\n / sum by(server_id)(nats_varz_jetstream_config_max_storage{cluster=~\"$cluster\"})\r\n ) > 90) or\r\n 1 * sgn(max(\r\n 100 * sum by(server_id)(nats_varz_jetstream_stats_storage{cluster=~\"$cluster\"})\r\n / sum by(server_id)(nats_varz_jetstream_config_max_storage{cluster=~\"$cluster\"})\r\n ) <= 90) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"/d/e17d0b7f-9771-4cb8-adf9-56cbaef3fff6/aio-service-dp-messagestore\",\"\",\"\")\r\n ,\"_\",\"Store Utilization\",\"\",\"\") or \r\n vector(0)>0\r\n# ),\"_\",\"Overall Health\",\"\",\"\")", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "B" + } + ], + "title": "Service Health", + "transformations": [], + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Click for Data Processor details", + "url": "/d/e57b7777-71be-43a8-87bd-d917391b154f/aio-service-dp-overview?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 0.8 + }, + { + "color": "dark-green", + "value": 1 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Self-test error rate" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "line" + }, + { + "id": "custom.lineWidth", + "value": 3 + }, + { + "id": "custom.fillOpacity", + "value": 5 + }, + { + "id": "custom.pointSize", + "value": 5 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 0, + 5 + ], + "fill": "dot" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Self-test output (msgs/min)" + }, + "properties": [ + { + "id": "custom.axisSoftMax", + "value": 3 + }, + { + "id": "mappings", + "value": [ + { + "options": { + "0": { + "color": "#808080", + "index": 0 + } + }, + "type": "value" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 27 + }, + "id": 28, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "asc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": " label_replace(#label_replace(\r\n #(min(sgn(\r\n max(round(rate(\r\n aio_dp_stage_incoming_messages{cluster=~\"$cluster\", stage_type=~\"output/.*\", cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}[$__rate_interval]\r\n )*60))#)) or vector(-1))\r\n #,\"url\",\"/d/f46e5384-d78d-480a-911c-0328cb20b224/e4k-ping\",\"\",\"\")\r\n ,\"_\",\"Self-test output (msgs/min)\",\"\",\"\") or\r\n #stage_incoming_messages{cluster=~\"$cluster\", stage_type=~\"output/.*\", cloud_resource_id=~\"$aio_dp_self_test_pipeline\"} or\r\n label_replace(\r\n #0 * sgn(\r\n 0 < round(sum(increase(aio_dp_stage_errors{cluster=~\"$cluster\",cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}[$__rate_interval])))#) or\r\n #or vector(3)\r\n ,\"_\",\"Self-test error rate\",\"\",\"\") or\r\n vector(0)>0", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Self-test Output and Errors", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Click for Data Processor details", + "url": "/d/e57b7777-71be-43a8-87bd-d917391b154f/aio-service-dp-overview?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "hidden-timeline" + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Self-test latency threshold" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Self-test pipeline latency over threshold" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.lineWidth", + "value": 3 + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 31 + }, + "id": 29, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n max(histogram_quantile(0.95, rate(\r\n aio_dp_pipeline_latency_bucket{cluster=~\"$cluster\",cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}[5m]\r\n )))\r\n ,\"_\",\"Self-test pipeline latency\",\"\",\"\") or\r\nlabel_replace($aio_dp_latency_threshold_ms * sgn(\r\n max(histogram_quantile(0.95, rate(\r\n aio_dp_pipeline_latency_bucket{cluster=~\"$cluster\",cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}[5m]\r\n )))\r\n ),\"_\",\"Self-test latency threshold\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n max(histogram_quantile(0.95, rate(\r\n aio_dp_pipeline_latency_bucket{cluster=~\"$cluster\",cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}[5m]\r\n ))) >= $aio_dp_latency_threshold_ms\r\n ,\"x\",\"Over threshold\",\"\",\"\")\r\n ,\"_\",\"Self-test pipeline latency over threshold\",\"\",\"\") or\r\nlabel_replace(vector(0),\"_\",\"hidden-timeline\",\"\",\"\") or\r\nvector(0)>0", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + } + ], + "title": "Self-test Pipeline Latency", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 35 + }, + "id": 12, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Golden Metrics\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [ + { + "options": { + "match": "null+nan", + "result": { + "color": "transparent", + "index": 0 + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".*s$" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisLabel", + "value": "total count" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*[/]sec[)]$" + }, + "properties": [ + { + "id": "custom.axisLabel", + "value": "throughput (msgs/sec)" + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 37 + }, + "id": 50, + "links": [ + { + "targetBlank": true, + "title": "Show details on Data Processor - Overview", + "url": "/d/e57b7777-71be-43a8-87bd-d917391b154f/aio-service-dp-overview?${__all_variables}&${__url_time_range}" + } + ], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(#quantile_over_time($latency_percentile,\r\n sum(rate(aio_dp_reader_incoming_messages{cluster=\"$cluster\"}[$__rate_interval]))\r\n #[$latency_quantile_range:])\r\n ,\"_\",\"Input (msgs/sec)\",\"\",\"\") or\r\nlabel_replace(#quantile_over_time($latency_percentile,\r\n sum(rate(aio_dp_stage_incoming_messages{cluster=\"$cluster\",stage_type=~\"output/.*\"}[$__rate_interval]))\r\n #[$latency_quantile_range:])\r\n ,\"_\",\"Output (msgs/sec)\",\"\",\"\") or\r\nlabel_replace(\r\n count(count by (cloud_resource_id, runner_partition) (rate(aio_dp_runner_info{cluster=\"$cluster\"}[$__rate_interval])))\r\n ,\"_\",\"Runners (count)\",\"\",\"\") or\r\nlabel_replace(\r\n count(count by (cloud_resource_id, stage_id) (rate(aio_dp_stage_info{cluster=\"$cluster\"}[$__rate_interval])))\r\n ,\"_\",\"Stages (count)\",\"\",\"\") or\r\n# label_replace(vector(1),\"_\",\"TODO: Usage/Volume\",\"\",\"\") or\r\nvector(0) > 0", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Usage/Volume", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Success Rate" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 4 + }, + { + "id": "custom.axisSoftMin", + "value": 0 + }, + { + "id": "custom.axisSoftMax", + "value": 101 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*(Errors)$" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "unit", + "value": "none" + }, + { + "id": "custom.axisLabel", + "value": "Error Count" + }, + { + "id": "custom.drawStyle", + "value": "bars" + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "custom.axisSoftMin", + "value": 0 + }, + { + "id": "custom.axisSoftMax", + "value": 20 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 37 + }, + "id": 51, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n ( (sum(rate(aio_dp_reader_incoming_messages{cluster=\"$cluster\"}[$__rate_interval])) > 0 or vector(0))\r\n / (sum(rate(aio_dp_reader_incoming_messages{cluster=\"$cluster\"}[$__rate_interval])) > 0 or vector(1))\r\n ) and\r\n (sum(rate(aio_dp_stage_incoming_messages{cluster=\"$cluster\",stage_type=~\"output/.*\"}[$__rate_interval])) > 0)\r\n or \r\n ( (sum(rate(aio_dp_reader_incoming_messages{cluster=\"$cluster\"}[$__rate_interval])) > 0 or vector(0))\r\n / (sum(rate(aio_dp_reader_incoming_messages{cluster=\"$cluster\"}[$__rate_interval])) > 0 or vector(1))\r\n ) >0 and\r\n (sum(rate(aio_dp_stage_incoming_messages{cluster=\"$cluster\",stage_type=~\"output/.*\"}[$__rate_interval])) == 0) * 0\r\n ,\"_\",\".Success Rate\",\"\",\"\") * 100 or\r\nlabel_replace(\r\n sum(rate(aio_dp_stage_errors{cluster=\"$cluster\"}[$__rate_interval])) or vector(0)\r\n ,\"_\",\"Stage Errors\",\"\",\"\") or\r\nlabel_replace(\r\nsum(rate(aio_dp_reader_errors{cluster=\"$cluster\"}[$__rate_interval])) or vector(0)\r\n ,\"_\",\"Reader Errors\",\"\",\"\") or\r\n#label_replace(vector(1),\"_\",\"TODO: Success Rate\",\"\",\"\") or\r\nvector(0) > 0", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Success Rate/Errors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "Self-test.*" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 0, + 10 + ], + "fill": "dot" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 37 + }, + "id": 52, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#ping_latency_last_value_ms{cluster=\"$cluster\"} or\r\nmax by (_)(\r\n label_replace(label_replace(label_replace(#quantile_over_time($latency_percentile,\r\n histogram_quantile($latency_percentile, sum(rate(aio_dp_pipeline_latency_bucket{cluster=\"$cluster\",cloud_resource_id!~\"$aio_dp_self_test_pipeline\"}[$latency_quantile_range])) by (le))\r\n #[$latency_quantile_range:])\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"RUM Latency $1\",\"pout\",\"(.*)\") or\r\n label_replace(label_replace(label_replace(#quantile_over_time($latency_percentile,\r\n histogram_quantile($latency_percentile, sum(rate(aio_dp_pipeline_latency_bucket{cluster=\"$cluster\"}[$latency_quantile_range])) by (le,cloud_resource_id))\r\n #[$latency_quantile_range:])\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"Worst Pipeline Latency $1\",\"pout\",\"(.*)\") or\r\n label_replace(label_replace(label_replace(#quantile_over_time($latency_percentile,\r\n histogram_quantile($latency_percentile, rate(aio_dp_pipeline_latency_bucket{cluster=~\"$cluster\",cloud_resource_id=~\"$aio_dp_self_test_pipeline\"}[$latency_quantile_range]))\r\n #[$latency_quantile_range:])\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"Self-test Pipeline Latency $1\",\"pout\",\"(.*)\") or\r\n vector(0)>0) or\r\n#label_replace(vector(1),\"_\",\"TODO: Latency\",\"\",\"\") or\r\nvector(0)>0", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(histogram_quantile(0.95, rate(pipeline_latency_bucket{cluster=~\"$cluster|int-virtual-02\",cloud_resource_id=~\".*self-test.*\"}[$__rate_interval])),\"_\",\"P95\",\"\",\"\") or\r\nvector(0)>0", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "No saturation data available for ${component:text}", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Backpressure Rejection %" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 3 + }, + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "# rejected by .*" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "bars" + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisLabel", + "value": "Packet Rejected Count" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 37 + }, + "id": 53, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#max by(_)(\r\n#label_replace(clamp( # NOTE: data for percent is really choppy; need to clamp, take rate over longer window (and offset), and then \r\n# # truncate to zero when no backpressure is detected in the $__rate_interval to get a less noisy, more accurate view of percentage\r\n# sum(rate(backpressure_packets_rejected{pod_type=\"BE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[60m] offset -30m)) * 100 / \r\n# sum(rate(publishes_received{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[60m] offset -30m))\r\n# and sum(rate(backpressure_packets_rejected{pod_type=\"BE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[$__rate_interval])) > 0 or vector(0)\r\n# ,0,100),\"_\",\"Backpressure Rejection %\",\"\",\"\") or\r\n#label_replace(sum by(short_hostname)(\r\n# label_replace(\r\n# sum by(hostname) (ceil(rate(backpressure_packets_rejected{cluster=~\"$cluster\", instance=~\"$namespace\"}[$__rate_interval])*60))\r\n# ,\"short_hostname\", \"$1\", \"hostname\", \"(.*).azedge-dmqtt-backend.*\"))\r\n# ,\"_\",\"# rejected by $1\",\"short_hostname\",\"(.*)\") > 0 or\r\n# vector(0)>0\r\n#) or\r\n#label_replace(vector(0),\"_\",\"TODO: Saturation\",\"\",\"\") or\r\nvector(0)>0", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Saturation", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 45 + }, + "id": 11, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Infrastructure Workload Health\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "Click for more details", + "url": "/d/eef9bf1c-b27a-4e86-a7f0-2a39cdfbeeca/health-infrastructure?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red" + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 47 + }, + "id": 31, + "links": [ + { + "targetBlank": true, + "title": "See infra workload health for all components", + "url": "/d/E5cCeHj4z/health-infra-workload?${cluster:queryparam}&${__url_time_range}" + } + ], + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.9, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Workload Readiness health\r\n############################\r\nlabel_replace(min(\r\navg(label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n label_replace(label_join(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n / label_replace(label_join(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n) by (workload) >=0 \r\n) or vector(0),\"_\",\"Workload Readiness\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Restart Health:\r\n############################\r\nlabel_replace(\r\n sgn(sum_over_time(sum(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[10m:1m]\r\n )*60)[1h:]) > 5) * 0.0 # RED: Cumulative restarts over X(5) time greater than Y(1h)\r\n or (max(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[5m:1m]\r\n )*60*5) > 0) * 0.5 # YELLOW: restarts detected but below Red threshold\r\n or sgn(max(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}\r\n + 1 >= 0))\r\n #or vector(1) # Healthy\r\n ,\"_\",\"Container Restart Health\",\"\",\"\")\r\n## uncomment below to t-shoot this health metric\r\n# or label_replace(sum_over_time(sum(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[10m:1m])*60)[1h:]),\"_\",\"Total-restarts-over-time\",\"\",\"\")\r\n# or label_replace((max(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[5m:1m])*60*5) without (__name__,uid,instance,job) > 0),\"_\",\"restart\",\"\",\"\") # Base query for counting restarts\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container CPU top-level health\r\n################################\r\nlabel_replace(\r\nmin(sgn( # Check for throttling > N indicating container is exceeding its CPU limits\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m]) \r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m])\r\n >= 0.60) # If throttle create is greater than this percentage, we'll multiply sgn by 0.5 to show as error (or warning depending on threshold coloring)\r\n ) # by (namespace,container) # These are commented out for top-level\r\n * 0.0\r\nor\r\nmin(sgn( # Check for throttling > N indicating container is exceeding its CPU limits\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m]) \r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m])\r\n >= 0.40) # If throttle create is greater than this percentage, we'll multiply sgn by 0.5 to show as error (or warning depending on threshold coloring)\r\n ) # by (namespace,container) # These are commented out for top-level\r\n * 0.5\r\nor\r\nmin( # Check to see if container is missing CPU Limits configuration\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"cpu\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n ) #by (namespace,container) # These are commented out for top-level\r\n,\"_\",\"Container CPU Health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Memory Health:\r\n###########################\r\nlabel_replace(\r\nmin( # Look for high memory utilization\r\n sgn((\r\n max(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container)\r\n / min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"memory\",pod=~\"${component:raw}\"}) by (namespace, container)\r\n ) >= .95) - 0.5 # show health state of 0.5 if container memory utilization >= 95%\r\n) #by (container) \r\nor\r\nmin( # Look for missing limits which we will show as 0 if missing\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"memory\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n) #by (container) \r\n,\"_\",\"Container Memory health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Health Summary", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "max(rate(container_cpu_usage_seconds_total{namespace=~\"alice-springs|symphony-k8s-system\",container=\"\",cpu=\"total\"}[5m])*300 > 0) ": "POD CPU (max)", + "min( # Workload ready percents (for deployment, daemonset, replicaset, and statefulset)\r\n label_replace(label_join(\r\n {job=\"kube-state-metrics\",namespace=~\"alice-springs|symphony-k8s-system\",\r\n __name__=~\"kube_(deployment|daemonset|replicaset|statefulset)_status_(replicas_ready|ready_replicas|number_ready)\"}\r\n ,\"workload\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n / label_replace(label_join(\r\n {job=\"kube-state-metrics\",namespace=~\"alice-springs|symphony-k8s-system\",\r\n __name__=~\"kube_(deployment|daemonset|replicaset|statefulset)_status_(replicas|desired_number_scheduled)\"}\r\n ,\"workload\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n) #by (workloadType) #namespace) #, workloadType) #, workload)": "Workload ready health" + } + } + } + ], + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red" + }, + { + "color": "green", + "value": 20 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 6, + "y": 47 + }, + "id": 33, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(sum ( # by(workloadType) (\r\n#min(\r\n# label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n label_replace(label_join(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n),\"_\",\"Ready\",\"\",\"\")\r\n# / label_replace(label_join(\r\n# kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\"$namespace\",daemonset=~\"${component:raw}\"} or\r\n# kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\"$namespace\",deployment=~\"${component:raw}\"} or\r\n# kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\"$namespace\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n# ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n#) by (workload) >=0 ", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#min(\r\n# label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n# label_replace(label_join(\r\n# kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",deployment=~\"${component:raw}\"} or\r\n# kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",daemonset=~\"${component:raw}\"} or\r\n# kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n# / label_replace(label_join(\r\n label_replace(sum(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n ),\"_\",\"Requested\",\"\",\"\")\r\n# ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n#) by (workload) >=0 ", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Workloads", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 8, + "y": 47 + }, + "id": 35, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor label_replace(vector(0),\"status\",\"Ready\",\"\",\"\")\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "DaemonSets", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 10, + "y": 47 + }, + "id": 37, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor label_replace(vector(0),\"status\",\"Ready\",\"\",\"\") # this is to zero if no workloads of this type exist\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "Deployments", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 12, + "y": 47 + }, + "id": 39, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor \r\nlabel_replace(vector(0),\"status\",\"Ready\",\"\",\"\")\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "StatefulSets", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 1 + }, + { + "color": "dark-orange", + "value": 5 + }, + { + "color": "red", + "value": 10 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 14, + "y": 47 + }, + "id": 41, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Container Restarts\r\nlabel_replace(ceil(sum_over_time(sum(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[10m:1m])*60)[1h:])),\"_\",\"restarts\",\"\",\"\")\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "#EAB839", + "value": 40 + }, + { + "color": "red", + "value": 60 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percent containers with CPU Limits (%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "super-light-purple", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Usage (milli-cores)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisColorMode", + "value": "series" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Max Throttled (%)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "thresholds", + "seriesBy": "max" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 47 + }, + "id": 59, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\n(label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))*1000,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\") )\r\n# Percent of containers with limits defined\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"Percent containers with CPU Limits (%)\",\"\",\"\")\r\n# CPU Throttling:\r\nor label_replace(100*(max(\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n )),\"_\",\"CPU Max Throttled (%)\",\"\",\"\")\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(quantile_over_time(0.95,sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\nvector(0)>0\r\n# Sum of all limits defined, in Cores\r\nor label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# WIP:\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"WIP-PERCENT_WITH_LIMITS\",\"\",\"\")\r\nor label_replace(count(\r\n kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"})\r\n ,\"_\",\"WIP-NUMERATOR\",\"\",\"\")\r\nor label_replace(count(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) #without(cluster,container,cpu,id,image,instance,job,name,namespace,pod)\r\n ,\"_\",\"WIP-DENOMINATOR\",\"\",\"\")\r\n# ", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "CPU", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "#EAB839", + "value": 80 + }, + { + "color": "orange", + "value": 85 + }, + { + "color": "red", + "value": 90 + }, + { + "color": "dark-red", + "value": 95 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percent containers with Memory Limits (%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mem Working Bytes (MB)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisColorMode", + "value": "series" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mem Max Usage vs Limit (%)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "thresholds", + "seriesBy": "max" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 47 + }, + "id": 61, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory Usage (MB version)\r\n(label_replace(sum(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"Mem Working Bytes (MB)\",\"\",\"\") )\r\n# Percent containers with limits\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"memory\"}) /\r\n count(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}) *100\r\n ,\"_\",\"Percent containers with Memory Limits (%)\",\"\",\"\")\r\n# Max Mem % Usage:\r\nor label_replace(100*(max(\r\n max_over_time((max by(container)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}))[10m:])\r\n / max by(container)(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"memory\"})\r\n )),\"_\",\"Mem Max Usage vs Limit (%)\",\"\",\"\")\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(quantile_over_time(0.95,sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\nvector(0)>0\r\n# Sum of all limits defined, in Cores\r\nor label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# WIP:\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"WIP-PERCENT_WITH_LIMITS\",\"\",\"\")\r\nor label_replace(count(\r\n kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"})\r\n ,\"_\",\"WIP-NUMERATOR\",\"\",\"\")\r\nor label_replace(count(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) #without(cluster,container,cpu,id,image,instance,job,name,namespace,pod)\r\n ,\"_\",\"WIP-DENOMINATOR\",\"\",\"\")\r\n# ", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "milli-cores", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels._}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels._}.*" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Overall" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "number" + }, + "properties": [ + { + "id": "links" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 51 + }, + "id": 47, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(_)(\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum by(pod)(rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") or\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum (rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\".Overall\",\"\",\"\") or\r\nvector(0)>0)", + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + } + ], + "title": "CPU Usage by Workload", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "working bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels._}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels._}.*" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byType", + "options": "number" + }, + "properties": [ + { + "id": "links" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 51 + }, + "id": 48, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(_)(\r\nlabel_replace(\r\n sum by(pod)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") \r\n)\r\n##(label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))*1000,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\") )\r\n## and label_replace(max_over_time(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))[3d:]) < 0.2,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\")) # Show milli-cores if rate below 0.2 cores\r\n# CPU Time (cores version, if >= 0.2 cores)\r\n##or (label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval])),\"_\",\"CPU Usage (cores)\",\"\",\"\") \r\n## and label_replace(max_over_time(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))[3d:]) >= 0.2,\"_\",\"CPU Usage (cores)\",\"\",\"\")) # Show in cores if rate at or above 0.2 cores\r\n# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(max_over_time(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\n# Sum of all limits defined, in Cores\r\n##or label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# CPU Throttling:\r\n##or label_replace(100*(max(\r\n## rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n## / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n## )),\"_\",\"CPU Max Throttled (%)\",\"\",\"\")\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Memory Usage by Workload", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Click on data series to drill down into pod details", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "milli-cores", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels.pod}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels.pod}" + } + ], + "mappings": [ + { + "options": { + "match": "null+nan", + "result": { + "color": "transparent", + "index": 0 + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Overall" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 59 + }, + "id": 56, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(pod)(\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum by(pod)(rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\"$1\",\"pod\",\"(.*)\") or #,\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") or\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum (rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"pod\",\".Overall\",\"\",\"\") or\r\nvector(0)>0)", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(_)(\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum by(pod)(rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") or\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum (rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\".Overall\",\"\",\"\") or\r\nvector(0)>0)", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "CPU Usage by Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Click on data series to drill down into pod details", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "working bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels.pod}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels.pod}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 59 + }, + "id": 57, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory working bytes\r\nmax by(pod)(\r\nlabel_replace(\r\n sum by(pod)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") \r\n)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory working bytes\r\nmax by(_)(\r\nlabel_replace(\r\n sum by(pod)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") \r\n)", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Memory Usage by Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 67 + }, + "id": 13, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Errors & Logs\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "yellow", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PodName" + }, + "properties": [ + { + "id": "custom.width", + "value": 300 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Reason" + }, + "properties": [ + { + "id": "custom.width", + "value": 112 + }, + { + "id": "custom.align", + "value": "center" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "Failed": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ] + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Count" + }, + "properties": [ + { + "id": "custom.width", + "value": 114 + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "color", + "value": { + "mode": "continuous-BlPu" + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.width", + "value": 200 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Message" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 69 + }, + "id": 55, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Count" + } + ] + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "azureLogAnalytics": { + "query": "KubeEvents\r\n| where TimeGenerated > $__timeFrom() and TimeGenerated <= $__timeTo()\r\n| where ClusterName == '$cluster'\r\n| where Name matches regex '${component:raw}'\r\n//| order by TimeGenerated desc\r\n| order by LastSeen desc, FirstSeen desc, TimeGenerated desc\r\n| project-rename PodName = Name\r\n| project FirstSeen, LastSeen, Count, PodName, Reason, Message\r\n| take 10", + "resources": [ + "/subscriptions/af342bf1-1ace-41df-902c-47921400551b" + ], + "resultFormat": "table" + }, + "azureMonitor": { + "allowedTimeGrainsMs": [], + "timeGrain": "auto" + }, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "queryType": "Azure Log Analytics", + "refId": "A" + } + ], + "title": "Last 10 Kube Events entries (from $cluster)", + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 77 + }, + "id": 14, + "links": [ + { + "targetBlank": true, + "title": "Open ${component_text} - Overview page", + "url": "/d/e57b7777-71be-43a8-87bd-d917391b154f/aio-service-dp-overview?${__all_variables}&${__url_time_range}" + } + ], + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   ${component_text}-specific\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "yellow", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PodName" + }, + "properties": [ + { + "id": "custom.width", + "value": 300 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Reason" + }, + "properties": [ + { + "id": "custom.width", + "value": 112 + }, + { + "id": "custom.align", + "value": "center" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "Failed": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ] + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Count" + }, + "properties": [ + { + "id": "custom.width", + "value": 114 + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "color", + "value": { + "mode": "continuous-BlPu" + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.width", + "value": 200 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Message" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ContainerName" + }, + "properties": [ + { + "id": "custom.width", + "value": 193 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "LogMessage" + }, + "properties": [ + { + "id": "custom.width", + "value": 1656 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "LogSource" + }, + "properties": [ + { + "id": "custom.width", + "value": 140 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 79 + }, + "id": 63, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "azureLogAnalytics": { + "query": "ContainerLogV2\r\n| where TimeGenerated >= $__timeFrom() and TimeGenerated <= $__timeTo()\r\n| where _ResourceId contains '$cluster'\r\n| where ContainerName contains \"dp\"\r\n| order by TimeGenerated desc\r\n| project TimeGenerated, PodName, ContainerName, LogSource, LogMessage\r\n| take 100", + "resources": [ + "/subscriptions/af342bf1-1ace-41df-902c-47921400551b" + ], + "resultFormat": "table" + }, + "azureMonitor": { + "allowedTimeGrainsMs": [], + "timeGrain": "auto" + }, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "queryType": "Azure Log Analytics", + "refId": "A" + } + ], + "title": "Last 100 Log entries (from $cluster)", + "type": "table" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "description": "Defines the service Component this report focuses on.", + "hide": 2, + "name": "component", + "query": "${VAR_COMPONENT}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_COMPONENT}", + "text": "${VAR_COMPONENT}", + "selected": false + }, + "options": [ + { + "value": "${VAR_COMPONENT}", + "text": "${VAR_COMPONENT}", + "selected": false + } + ] + }, + { + "description": "Defines the service Component this report focuses on.", + "hide": 2, + "name": "component_text", + "query": "${VAR_COMPONENT_TEXT}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_COMPONENT_TEXT}", + "text": "${VAR_COMPONENT_TEXT}", + "selected": false + }, + "options": [ + { + "value": "${VAR_COMPONENT_TEXT}", + "text": "${VAR_COMPONENT_TEXT}", + "selected": false + } + ] + }, + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_node_status_condition", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "kube_node_status_condition", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*cluster=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "hide": 2, + "includeAll": true, + "multi": true, + "name": "namespace", + "options": [], + "query": { + "query": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "description": "Pipeline RegEx for the self-test pipeline", + "hide": 2, + "name": "aio_dp_self_test_pipeline", + "query": "${VAR_AIO_DP_SELF_TEST_PIPELINE}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_AIO_DP_SELF_TEST_PIPELINE}", + "text": "${VAR_AIO_DP_SELF_TEST_PIPELINE}", + "selected": false + }, + "options": [ + { + "value": "${VAR_AIO_DP_SELF_TEST_PIPELINE}", + "text": "${VAR_AIO_DP_SELF_TEST_PIPELINE}", + "selected": false + } + ] + }, + { + "hide": 2, + "name": "latency_percentile", + "query": "${VAR_LATENCY_PERCENTILE}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_LATENCY_PERCENTILE}", + "text": "${VAR_LATENCY_PERCENTILE}", + "selected": false + }, + "options": [ + { + "value": "${VAR_LATENCY_PERCENTILE}", + "text": "${VAR_LATENCY_PERCENTILE}", + "selected": false + } + ] + }, + { + "auto": true, + "auto_count": 300, + "auto_min": "5m", + "current": { + "selected": false, + "text": "auto", + "value": "$__auto_interval_latency_quantile_range" + }, + "hide": 2, + "name": "latency_quantile_range", + "options": [ + { + "selected": true, + "text": "auto", + "value": "$__auto_interval_latency_quantile_range" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "15m", + "value": "15m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "3h", + "value": "3h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "24h", + "value": "24h" + } + ], + "query": "5m,10m,15m,1h,3h,6h,24h", + "queryValue": "", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + }, + { + "hide": 2, + "name": "aio_dp_error_threshold", + "query": "${VAR_AIO_DP_ERROR_THRESHOLD}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_AIO_DP_ERROR_THRESHOLD}", + "text": "${VAR_AIO_DP_ERROR_THRESHOLD}", + "selected": false + }, + "options": [ + { + "value": "${VAR_AIO_DP_ERROR_THRESHOLD}", + "text": "${VAR_AIO_DP_ERROR_THRESHOLD}", + "selected": false + } + ] + }, + { + "hide": 2, + "name": "aio_dp_nats_utilization_threshold", + "query": "${VAR_AIO_DP_NATS_UTILIZATION_THRESHOLD}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_AIO_DP_NATS_UTILIZATION_THRESHOLD}", + "text": "${VAR_AIO_DP_NATS_UTILIZATION_THRESHOLD}", + "selected": false + }, + "options": [ + { + "value": "${VAR_AIO_DP_NATS_UTILIZATION_THRESHOLD}", + "text": "${VAR_AIO_DP_NATS_UTILIZATION_THRESHOLD}", + "selected": false + } + ] + }, + { + "hide": 2, + "name": "aio_dp_latency_threshold_ms", + "query": "${VAR_AIO_DP_LATENCY_THRESHOLD_MS}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_AIO_DP_LATENCY_THRESHOLD_MS}", + "text": "${VAR_AIO_DP_LATENCY_THRESHOLD_MS}", + "selected": false + }, + "options": [ + { + "value": "${VAR_AIO_DP_LATENCY_THRESHOLD_MS}", + "text": "${VAR_AIO_DP_LATENCY_THRESHOLD_MS}", + "selected": false + } + ] + }, + { + "hide": 2, + "name": "aio_dp_error_rate", + "query": "${VAR_AIO_DP_ERROR_RATE}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_AIO_DP_ERROR_RATE}", + "text": "${VAR_AIO_DP_ERROR_RATE}", + "selected": false + }, + "options": [ + { + "value": "${VAR_AIO_DP_ERROR_RATE}", + "text": "${VAR_AIO_DP_ERROR_RATE}", + "selected": false + } + ] + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "aio-health-service-dp", + "uid": "e7f4802e-d73b-4f06-a84c-715cdc42fb35", + "version": 35, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-health-service-mq-1698853600657.json b/samples/dashboard/grafana-dashboards/aio-health-service-mq-1698853600657.json new file mode 100644 index 0000000..fa3a491 --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-health-service-mq-1698853600657.json @@ -0,0 +1,3861 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + }, + { + "name": "DS_AZURE_MONITOR", + "label": "Azure Monitor", + "description": "", + "type": "datasource", + "pluginId": "grafana-azure-monitor-datasource", + "pluginName": "Azure Monitor" + }, + { + "name": "VAR_COMPONENT", + "type": "constant", + "label": "component", + "value": "^(aio-mq-).*", + "description": "" + }, + { + "name": "VAR_COMPONENT_TEXT", + "type": "constant", + "label": "component_text", + "value": "AIO MQ", + "description": "" + }, + { + "name": "VAR_LATENCY_PERCENTILE", + "type": "constant", + "label": "latency_percentile", + "value": "0.95", + "description": "" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "grafana-azure-monitor-datasource", + "name": "Azure Monitor", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "piechart", + "name": "Pie chart", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "state-timeline", + "name": "State timeline", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 8, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n Azure Edge Services - Message Queue Health\n
\n
\n   Scenario Health (SLO/RUM) related to ${component_text}\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 60, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for ${component_text} ${__field.labels._}", + "url": "${__field.labels.url}?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#7f7f7f", + "value": null + }, + { + "color": "semi-dark-red", + "value": 0 + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "semi-dark-green", + "value": 1 + }, + { + "color": "#7f7f7f", + "value": 404 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "MQ Overall Health" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 1 + }, + { + "id": "links" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 3 + }, + "id": 62, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.72, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(min(\r\n label_replace(label_replace(\r\n (1 - min(\r\n 1 * sgn(\r\n sum(\r\n rate(aio_mq_authentication_failures{cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])\r\n )\r\n <= 20) or\r\n 0 * sgn(\r\n sum(\r\n rate(aio_mq_authentication_failures{cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])\r\n )\r\n > 20)) or vector(0))\r\n ,\"url\",\"/d/f41cdbe5-4075-4f05-aeb2-a34b5b46571c/aio-service-mq-connect\",\"\",\"\")\r\n ,\"_\",\"Authentication failures\",\"\",\"\") or\r\n label_replace(label_replace(\r\n (1 - min(\r\n 1 * sgn(\r\n sum(\r\n rate(aio_mq_authorization_deny{cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])\r\n )\r\n <= 20) or\r\n 0 * sgn(\r\n sum(\r\n rate(aio_mq_authorization_deny{cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])\r\n )\r\n > 20)) or vector(0))\r\n ,\"url\",\"/d/f41cdbe5-4075-4f05-aeb2-a34b5b46571c/aio-service-mq-connect\",\"\",\"\")\r\n ,\"_\",\"Authorization failures\",\"\",\"\") or \r\n label_replace(label_replace(\r\n (1 - min(\r\n 1 * sgn(\r\n sum(rate(aio_mq_backpressure_packets_rejected{pod_type=\"BE\", cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])) / \r\n sum(quantile_over_time(.95, rate(aio_mq_publishes_received{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[2m])[30m:]))\r\n <= 0.05) or\r\n 0 * sgn(\r\n sum(rate(aio_mq_backpressure_packets_rejected{pod_type=\"BE\", cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])) / \r\n sum(quantile_over_time(.95, rate(aio_mq_publishes_received{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[2m])[30m:]))\r\n > 0.05)) or vector(0))\r\n ,\"url\",\"/d/eb3949b9-da3a-4b9e-8573-beb5507617a9/aio-service-mq-clusterperf\",\"\",\"\")\r\n ,\"_\",\"Backpressure\",\"\",\"\") or\r\n vector(0) > 0 # Tail; not shown\r\n),\"_\",\"MQ Overall Health\",\"\",\"\")\r\n", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#label_replace(min(\r\n label_replace(label_replace(\r\n (1 - min(\r\n 1 * sgn(\r\n sum(\r\n rate(aio_mq_authentication_failures{cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])\r\n )\r\n <= 20) or\r\n 0 * sgn(\r\n sum(\r\n rate(aio_mq_authentication_failures{cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])\r\n )\r\n > 20)) or vector(404))\r\n ,\"url\",\"/d/f41cdbe5-4075-4f05-aeb2-a34b5b46571c/aio-service-mq-connect\",\"\",\"\")\r\n ,\"_\",\"Authentication failures\",\"\",\"\") or\r\n label_replace(label_replace(\r\n (1 - min(\r\n 1 * sgn(\r\n sum(\r\n rate(aio_mq_authorization_deny{cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])\r\n )\r\n <= 20) or\r\n 0 * sgn(\r\n sum(\r\n rate(aio_mq_authorization_deny{cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])\r\n )\r\n > 20)) or vector(404))\r\n ,\"url\",\"/d/f41cdbe5-4075-4f05-aeb2-a34b5b46571c/aio-service-mq-connect\",\"\",\"\")\r\n ,\"_\",\"Authorization failures\",\"\",\"\") or \r\n label_replace(label_replace(\r\n (1 - min(\r\n 1 * sgn(\r\n sum(rate(aio_mq_backpressure_packets_rejected{pod_type=\"BE\", cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])) / \r\n sum(quantile_over_time(.95, rate(aio_mq_publishes_received{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[2m])[30m:]))\r\n <= 0.05) or\r\n 0 * sgn(\r\n sum(rate(aio_mq_backpressure_packets_rejected{pod_type=\"BE\", cluster=~\"$cluster\", instance=~\"$namespace\", category!=\"broker_selftest\"}[2m])) / \r\n sum(quantile_over_time(.95, rate(aio_mq_publishes_received{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[2m])[30m:]))\r\n > 0.05)) or vector(404))\r\n ,\"url\",\"/d/eb3949b9-da3a-4b9e-8573-beb5507617a9/aio-service-mq-clusterperf\",\"\",\"\")\r\n ,\"_\",\"Backpressure\",\"\",\"\") or\r\n vector(0) > 0 # Tail; not shown\r\n#),\"_\",\"MQ Overall Health\",\"\",\"\")", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "B" + } + ], + "title": "Service Health", + "transformations": [], + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "dash": [ + 3, + 6 + ], + "fill": "dot" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for ${component_text} Authentication failures", + "url": "d/f41cdbe5-4075-4f05-aeb2-a34b5b46571c/aio-service-mq-connect?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-green", + "value": null + }, + { + "color": "yellow", + "value": 0.8 + }, + { + "color": "dark-red", + "value": 1 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 3 + }, + "id": 63, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "asc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum by (category) (rate(aio_mq_authentication_failures{cluster=~\"$cluster\", instance=~\"$namespace\"}[$__rate_interval]))", + "hide": false, + "legendFormat": "{{category}}", + "range": true, + "refId": "A" + } + ], + "title": "Authentication failure rate", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "dash": [ + 3, + 6 + ], + "fill": "dot" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for ${component_text} Authorization failures", + "url": "/d/f41cdbe5-4075-4f05-aeb2-a34b5b46571c/aio-service-mq-connect?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-green", + "value": null + }, + { + "color": "yellow", + "value": 0.8 + }, + { + "color": "dark-red", + "value": 1 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 65, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "asc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (category) (rate(aio_mq_authorization_deny{cluster=~\"$cluster\", instance=~\"$namespace\"}[$__rate_interval]))", + "hide": false, + "instant": false, + "legendFormat": "{{category}}", + "range": true, + "refId": "B" + } + ], + "title": "Authorization failure rate", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "dash": [ + 3, + 6 + ], + "fill": "dot" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for ${component_text} Backpressure", + "url": "/d/eb3949b9-da3a-4b9e-8573-beb5507617a9/aio-service-mq-clusterperf?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 0.8 + }, + { + "color": "dark-green", + "value": 1 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "hidden-timeline" + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 7 + }, + "id": 64, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(clamp( # NOTE: data for percent is really choppy; need to clamp, take rate over longer window (and offset), and then \r\n # truncate to zero when no backpressure is detected in the $__rate_interval to get a less noisy, more accurate view of percentage\r\n sum(rate(aio_mq_backpressure_packets_rejected{pod_type=\"BE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[60m] offset -30m)) * 100 / \r\n sum(rate(aio_mq_publishes_received{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[60m] offset -30m))\r\n and sum(rate(aio_mq_backpressure_packets_rejected{pod_type=\"BE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[$__rate_interval])) > 0\r\n or vector(0)\r\n ,0,100),\"_\",\"Backpressure Rejection %\",\"\",\"\") or\r\nvector(0)>0\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Backpressure rejections %", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 10, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Service Health (Synthetics/Self-test)\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 60, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for ${component_text} ${__field.labels._}", + "url": "${__field.labels.url}?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#7f7f7f", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + }, + { + "color": "#7f7f7f", + "value": 404 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "MQ Overall Health" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 1 + }, + { + "id": "links" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 13 + }, + "id": 16, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.72, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(min(\r\n label_replace(label_replace((\r\n min(aio_mq_ping_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}) or vector(404))\r\n ,\"url\",\"/d/c58ee063-e5f3-4829-ae8f-0160127759cc/aio-service-mq-ping\",\"\",\"\")\r\n ,\"_\",\"Ping health\",\"\",\"\") or\r\n label_replace(label_replace((\r\n min(aio_mq_publish_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}) or vector(404))\r\n ,\"url\",\"/d/bf5237d2-7deb-4144-aa46-41e1c1629b30/aio-service-mq-publish\",\"\",\"\")\r\n ,\"_\",\"Publish health\",\"\",\"\") or \r\n label_replace(label_replace((\r\n min(aio_mq_subscribe_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}) or vector(404))\r\n ,\"url\",\"/d/b5d606dc-a841-4ec0-b7c5-4f1d37c4e877/aio-service-mq-subscribe\",\"\",\"\")\r\n ,\"_\",\"Subscribe health\",\"\",\"\") or \r\n vector(0) > 0 # Tail; not shown\r\n),\"_\",\"MQ Overall Health\",\"\",\"\")", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#label_replace(min(\r\n label_replace(label_replace((\r\n min(aio_mq_ping_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}) or vector(404))\r\n ,\"url\",\"/d/c58ee063-e5f3-4829-ae8f-0160127759cc/aio-service-mq-ping\",\"\",\"\")\r\n ,\"_\",\"Ping health\",\"\",\"\") or\r\n label_replace(label_replace((\r\n min(aio_mq_publish_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}) or vector(404))\r\n ,\"url\",\"/d/bf5237d2-7deb-4144-aa46-41e1c1629b30/aio-service-mq-publish\",\"\",\"\")\r\n ,\"_\",\"Publish health\",\"\",\"\") or \r\n label_replace(label_replace((\r\n min(aio_mq_subscribe_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}) or vector(404))\r\n ,\"url\",\"/d/b5d606dc-a841-4ec0-b7c5-4f1d37c4e877/aio-service-mq-subscribe\",\"\",\"\")\r\n ,\"_\",\"Subscribe health\",\"\",\"\") or \r\n vector(0) > 0 # Tail; not shown\r\n#),\"_\",\"MQ Overall Health\",\"\",\"\")", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "B" + } + ], + "title": "Service Health", + "transformations": [], + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMax": 101, + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "dash": [ + 3, + 6 + ], + "fill": "dot" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 0.8 + }, + { + "color": "dark-green", + "value": 1 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 13 + }, + "id": 28, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "asc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#label_replace(min(\r\n label_replace(\r\n (100*avg(aio_mq_ping_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}))\r\n ,\"_\",\"Ping health\",\"\",\"\") or\r\n label_replace(\r\n (100*avg(aio_mq_publish_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}))\r\n ,\"_\",\"Publish health\",\"\",\"\") or \r\n label_replace(\r\n (100*avg(aio_mq_subscribe_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}))\r\n ,\"_\",\"Subscribe health\",\"\",\"\") or \r\n vector(0) > 0 # Tail; not shown\r\n#),\"_\",\"MQ Overall Health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Self-test Details", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "affected count", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 0.8 + }, + { + "color": "dark-green", + "value": 1 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "hidden-timeline" + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 17 + }, + "id": 29, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#label_replace(min(\r\nmax by(_)(label_replace(label_join(\r\n label_replace(sgn(1+\r\n (min by(route)(aio_mq_ping_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}) < 1)\r\n ),\"_\",\"Ping health\",\"\",\"\") or\r\n label_replace(sgn(1+\r\n (min by(route)(aio_mq_publish_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}) < 1)\r\n ),\"_\",\"Publish health\",\"\",\"\") or \r\n label_replace(sgn(1+\r\n (min by(route)(aio_mq_subscribe_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}) < 1)\r\n ),\"_\",\"Subscribe health\",\"\",\"\") or \r\n vector(0) > 0 # Tail; not shown\r\n ,\"x\",\":\",\"_\",\"route\")\r\n ,\"_\",\"$2 - unhealthy $1\",\"x\",\"(.*) health:(.*)\")\r\n)#),\"_\",\"MQ Overall Health\",\"\",\"\")\r\nor label_replace(vector(0/0),\"_\",\"hidden-timeline\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Unhealthy Routes", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 12, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Golden Metrics\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".*s$" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisLabel", + "value": "total count" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*[/]sec[)]$" + }, + "properties": [ + { + "id": "custom.axisLabel", + "value": "throughput (msgs/sec)" + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.scaleDistribution", + "value": { + "log": 10, + "type": "symlog" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 23 + }, + "id": 50, + "links": [ + { + "targetBlank": true, + "title": "Show details on E4K Current Traffic", + "url": "/d/a-7FJxhVk/e4k-current-traffic-includes-selftest-traffic?${__all_variables}&${__url_time_range}" + } + ], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(quantile_over_time($latency_percentile,\r\n sum(rate(aio_mq_publishes_received{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[$__rate_interval])\r\n )[$latency_quantile_range:])\r\n ,\"_\",\"Inbound (msgs/sec)\",\"\",\"\") or\r\nlabel_replace(quantile_over_time($latency_percentile,\r\n sum(rate(aio_mq_publishes_sent{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[$__rate_interval])\r\n )[$latency_quantile_range:])\r\n ,\"_\",\"Outbound (msgs/sec)\",\"\",\"\") or\r\nlabel_replace(\r\n sum(aio_mq_total_subscriptions{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"})\r\n ,\"_\",\"Topic Subscriptions\",\"\",\"\") or\r\nlabel_replace(\r\n sum(aio_mq_connected_sessions{hostname=~\".*frontend.*\", cluster=~\"$cluster\", instance=~\"$namespace\"})\r\n ,\"_\",\"Connected Sessions\",\"\",\"\") or\r\n# label_replace(vector(1),\"_\",\"TODO: Usage/Volume\",\"\",\"\") or\r\nvector(0) > 0", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Usage/Volume", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMax": 101, + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Overall" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 4 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 23 + }, + "id": 51, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n (\r\n sum(aio_mq_ping_correctness{cluster=\"$cluster\"}) +\r\n sum(aio_mq_publish_route_replication_correctness{cluster=\"$cluster\"}) +\r\n sum(aio_mq_subscribe_route_replication_correctness{cluster=\"$cluster\"}) +\r\n 0) / (\r\n count(aio_mq_ping_correctness{cluster=\"$cluster\"}) +\r\n count(aio_mq_publish_route_replication_correctness{cluster=\"$cluster\"}) +\r\n count(aio_mq_subscribe_route_replication_correctness{cluster=\"$cluster\"}) +\r\n 0)\r\n ,\"_\",\".Overall\",\"\",\"\") * 100 or\r\nlabel_replace(\r\n sum(aio_mq_ping_correctness{cluster=\"$cluster\"}) / \r\n count(aio_mq_ping_correctness{cluster=\"$cluster\"})\r\n ,\"_\",\"Ping\",\"\",\"\") * 100 or\r\nlabel_replace(\r\n sum(aio_mq_publish_route_replication_correctness{cluster=\"$cluster\"}) / \r\n count(aio_mq_publish_route_replication_correctness{cluster=\"$cluster\"})\r\n ,\"_\",\"Publish\",\"\",\"\") * 100 or\r\nlabel_replace(\r\n sum(aio_mq_subscribe_route_replication_correctness{cluster=\"$cluster\"}) / \r\n count(aio_mq_subscribe_route_replication_correctness{cluster=\"$cluster\"})\r\n ,\"_\",\"Subscribe\",\"\",\"\") * 100 or\r\n#label_replace(vector(1),\"_\",\"TODO: Success Rate\",\"\",\"\") or\r\nvector(0) > 0", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Success Rate", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 23 + }, + "id": 52, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#ping_latency_last_value_ms{cluster=\"$cluster\"} or\r\nmax by (_)(\r\n label_replace(label_replace(label_replace(quantile_over_time($latency_percentile,\r\n aio_mq_ping_latency_last_value_ms{cluster=\"$cluster\"}[$latency_quantile_range])\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"Ping Latency $1\",\"pout\",\"(.*)\") or\r\n label_replace(label_replace(label_replace(quantile_over_time($latency_percentile,\r\n aio_mq_publish_latency_last_value_ms{cluster=\"$cluster\"}[$latency_quantile_range])\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"Publish Latency $1\",\"pout\",\"(.*)\") or\r\n label_replace(label_replace(label_replace(quantile_over_time($latency_percentile,\r\n aio_mq_subscribe_latency_last_value_ms{cluster=\"$cluster\"}[$latency_quantile_range])\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"Subscribe Latency $1\",\"pout\",\"(.*)\") or\r\n vector(0)>0) or\r\n#label_replace(vector(1),\"_\",\"TODO: Latency\",\"\",\"\") or\r\nvector(0)>0", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Latency", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 12, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Backpressure Rejection %" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 3 + }, + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "# rejected by .*" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "bars" + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisLabel", + "value": "Packet Rejected Count Per Second" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 23 + }, + "id": 53, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "max by(_)(\r\nlabel_replace(clamp( # NOTE: data for percent is really choppy; need to clamp, take rate over longer window (and offset), and then \r\n # truncate to zero when no backpressure is detected in the $__rate_interval to get a less noisy, more accurate view of percentage\r\n sum(rate(aio_mq_backpressure_packets_rejected{pod_type=\"BE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[60m] offset -30m)) * 100 / \r\n sum(rate(aio_mq_publishes_received{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[60m] offset -30m))\r\n and sum(rate(aio_mq_backpressure_packets_rejected{pod_type=\"BE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[$__rate_interval])) > 0 or vector(0)\r\n ,0,100),\"_\",\"Backpressure Rejection %\",\"\",\"\") or\r\nlabel_replace(sum by(short_hostname)(\r\n label_replace(\r\n sum by(hostname) (ceil(rate(aio_mq_backpressure_packets_rejected{cluster=~\"$cluster\", instance=~\"$namespace\"}[$__rate_interval])))\r\n ,\"short_hostname\", \"$1\", \"hostname\", \"aio-mq-dmqtt-backend-(.*)*\"))\r\n ,\"_\",\"# rejected by $1 (msg/s)\",\"short_hostname\",\"(.*)\") > 0 or\r\n vector(0)>0\r\n) or\r\n#label_replace(vector(1),\"_\",\"TODO: Saturation\",\"\",\"\") or\r\nvector(0)>0", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Saturation", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 11, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Infrastructure Workload Health\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "Click for more details", + "url": "/d/eef9bf1c-b27a-4e86-a7f0-2a39cdfbeeca/health-infrastructure?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 33 + }, + "id": 31, + "links": [ + { + "targetBlank": true, + "title": "See infra workload health for all components", + "url": "/d/E5cCeHj4z/health-infra-workload?${cluster:queryparam}&${__url_time_range}" + } + ], + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.9, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Workload Readiness health\r\n############################\r\nlabel_replace(min(\r\navg(label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n label_replace(label_join(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n / label_replace(label_join(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n) by (workload) >=0 \r\n) or vector(0),\"_\",\"Workload Readiness\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Restart Health:\r\n############################\r\nlabel_replace(\r\n sgn(sum_over_time(sum(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[10m:1m]\r\n )*60)[1h:]) > 5) * 0.0 # RED: Cumulative restarts over X(5) time greater than Y(1h)\r\n or (max(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[5m:1m]\r\n )*60*5) > 0) * 0.5 # YELLOW: restarts detected but below Red threshold\r\n or sgn(max(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}\r\n + 1 >= 0))\r\n #or vector(1) # Healthy\r\n ,\"_\",\"Container Restart Health\",\"\",\"\")\r\n## uncomment below to t-shoot this health metric\r\n# or label_replace(sum_over_time(sum(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[10m:1m])*60)[1h:]),\"_\",\"Total-restarts-over-time\",\"\",\"\")\r\n# or label_replace((max(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[5m:1m])*60*5) without (__name__,uid,instance,job) > 0),\"_\",\"restart\",\"\",\"\") # Base query for counting restarts\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container CPU top-level health\r\n################################\r\nlabel_replace(\r\nmin(sgn( # Check for throttling > N indicating container is exceeding its CPU limits\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m]) \r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m])\r\n >= 0.60) # If throttle create is greater than this percentage, we'll multiply sgn by 0.5 to show as error (or warning depending on threshold coloring)\r\n ) # by (namespace,container) # These are commented out for top-level\r\n * 0.0\r\nor\r\nmin(sgn( # Check for throttling > N indicating container is exceeding its CPU limits\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m]) \r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m])\r\n >= 0.40) # If throttle create is greater than this percentage, we'll multiply sgn by 0.5 to show as error (or warning depending on threshold coloring)\r\n ) # by (namespace,container) # These are commented out for top-level\r\n * 0.5\r\nor\r\nmin( # Check to see if container is missing CPU Limits configuration\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"cpu\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n ) #by (namespace,container) # These are commented out for top-level\r\n,\"_\",\"Container CPU Health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Memory Health:\r\n###########################\r\nlabel_replace(\r\nmin( # Look for high memory utilization\r\n sgn((\r\n max(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container)\r\n / min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"memory\",pod=~\"${component:raw}\"}) by (namespace, container)\r\n ) >= .95) - 0.5 # show health state of 0.5 if container memory utilization >= 95%\r\n) #by (container) \r\nor\r\nmin( # Look for missing limits which we will show as 0 if missing\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"memory\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n) #by (container) \r\n,\"_\",\"Container Memory health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Health Summary", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "max(rate(container_cpu_usage_seconds_total{namespace=~\"alice-springs|symphony-k8s-system\",container=\"\",cpu=\"total\"}[5m])*300 > 0) ": "POD CPU (max)", + "min( # Workload ready percents (for deployment, daemonset, replicaset, and statefulset)\r\n label_replace(label_join(\r\n {job=\"kube-state-metrics\",namespace=~\"alice-springs|symphony-k8s-system\",\r\n __name__=~\"kube_(deployment|daemonset|replicaset|statefulset)_status_(replicas_ready|ready_replicas|number_ready)\"}\r\n ,\"workload\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n / label_replace(label_join(\r\n {job=\"kube-state-metrics\",namespace=~\"alice-springs|symphony-k8s-system\",\r\n __name__=~\"kube_(deployment|daemonset|replicaset|statefulset)_status_(replicas|desired_number_scheduled)\"}\r\n ,\"workload\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n) #by (workloadType) #namespace) #, workloadType) #, workload)": "Workload ready health" + } + } + } + ], + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 20 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 6, + "y": 33 + }, + "id": 33, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(sum ( # by(workloadType) (\r\n#min(\r\n# label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n label_replace(label_join(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n),\"_\",\"Ready\",\"\",\"\")\r\n# / label_replace(label_join(\r\n# kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\"$namespace\",daemonset=~\"${component:raw}\"} or\r\n# kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\"$namespace\",deployment=~\"${component:raw}\"} or\r\n# kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\"$namespace\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n# ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n#) by (workload) >=0 ", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#min(\r\n# label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n# label_replace(label_join(\r\n# kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",deployment=~\"${component:raw}\"} or\r\n# kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",daemonset=~\"${component:raw}\"} or\r\n# kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n# / label_replace(label_join(\r\n label_replace(sum(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n ),\"_\",\"Requested\",\"\",\"\")\r\n# ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n#) by (workload) >=0 ", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Workloads", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 8, + "y": 33 + }, + "id": 35, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor label_replace(vector(0),\"status\",\"Ready\",\"\",\"\")\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "DaemonSets", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 10, + "y": 33 + }, + "id": 37, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor label_replace(vector(0),\"status\",\"Ready\",\"\",\"\") # this is to zero if no workloads of this type exist\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "Deployments", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 12, + "y": 33 + }, + "id": 39, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor \r\nlabel_replace(vector(0),\"status\",\"Ready\",\"\",\"\")\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "StatefulSets", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 1 + }, + { + "color": "dark-orange", + "value": 5 + }, + { + "color": "red", + "value": 10 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 14, + "y": 33 + }, + "id": 41, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Container Restarts\r\nlabel_replace(ceil(sum_over_time(sum(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[10m:1m])*60)[1h:])),\"_\",\"restarts\",\"\",\"\")\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 40 + }, + { + "color": "red", + "value": 60 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percent containers with CPU Limits (%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "super-light-purple", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Usage (milli-cores)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisColorMode", + "value": "series" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Max Throttled (%)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "thresholds", + "seriesBy": "max" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 33 + }, + "id": 59, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\n(label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))*1000,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\") )\r\n# Percent of containers with limits defined\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"Percent containers with CPU Limits (%)\",\"\",\"\")\r\n# CPU Throttling:\r\nor label_replace(100*(max(\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n )),\"_\",\"CPU Max Throttled (%)\",\"\",\"\")\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(quantile_over_time(0.95,sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\nvector(0)>0\r\n# Sum of all limits defined, in Cores\r\nor label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# WIP:\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"WIP-PERCENT_WITH_LIMITS\",\"\",\"\")\r\nor label_replace(count(\r\n kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"})\r\n ,\"_\",\"WIP-NUMERATOR\",\"\",\"\")\r\nor label_replace(count(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) #without(cluster,container,cpu,id,image,instance,job,name,namespace,pod)\r\n ,\"_\",\"WIP-DENOMINATOR\",\"\",\"\")\r\n# ", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "CPU", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 80 + }, + { + "color": "orange", + "value": 85 + }, + { + "color": "red", + "value": 90 + }, + { + "color": "dark-red", + "value": 95 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percent containers with Memory Limits (%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mem Working Bytes (MB)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisColorMode", + "value": "series" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mem Max Usage vs Limit (%)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "thresholds", + "seriesBy": "max" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 33 + }, + "id": 61, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory Usage (MB version)\r\n(label_replace(sum(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"Mem Working Bytes (MB)\",\"\",\"\") )\r\n# Percent containers with limits\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"memory\"}) /\r\n count(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}) *100\r\n ,\"_\",\"Percent containers with Memory Limits (%)\",\"\",\"\")\r\n# Max Mem % Usage:\r\nor label_replace(100*(max(\r\n max_over_time((max by(container)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}))[10m:])\r\n / max by(container)(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"memory\"})\r\n )),\"_\",\"Mem Max Usage vs Limit (%)\",\"\",\"\")\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(quantile_over_time(0.95,sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\nvector(0)>0\r\n# Sum of all limits defined, in Cores\r\nor label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# WIP:\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"WIP-PERCENT_WITH_LIMITS\",\"\",\"\")\r\nor label_replace(count(\r\n kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"})\r\n ,\"_\",\"WIP-NUMERATOR\",\"\",\"\")\r\nor label_replace(count(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) #without(cluster,container,cpu,id,image,instance,job,name,namespace,pod)\r\n ,\"_\",\"WIP-DENOMINATOR\",\"\",\"\")\r\n# ", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "milli-cores", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels._}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels._}.*" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Overall" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "number" + }, + "properties": [ + { + "id": "links" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 37 + }, + "id": 47, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(_)(\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum by(pod)(rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") or\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum (rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\".Overall\",\"\",\"\") or\r\nvector(0)>0)", + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + } + ], + "title": "CPU Usage by Workload", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "working bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels._}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels._}.*" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byType", + "options": "number" + }, + "properties": [ + { + "id": "links" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 37 + }, + "id": 48, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(_)(\r\nlabel_replace(\r\n sum by(pod)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") \r\n)\r\n##(label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))*1000,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\") )\r\n## and label_replace(max_over_time(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))[3d:]) < 0.2,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\")) # Show milli-cores if rate below 0.2 cores\r\n# CPU Time (cores version, if >= 0.2 cores)\r\n##or (label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval])),\"_\",\"CPU Usage (cores)\",\"\",\"\") \r\n## and label_replace(max_over_time(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))[3d:]) >= 0.2,\"_\",\"CPU Usage (cores)\",\"\",\"\")) # Show in cores if rate at or above 0.2 cores\r\n# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(max_over_time(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\n# Sum of all limits defined, in Cores\r\n##or label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# CPU Throttling:\r\n##or label_replace(100*(max(\r\n## rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n## / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n## )),\"_\",\"CPU Max Throttled (%)\",\"\",\"\")\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Memory Usage by Workload", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Click on data series to drill down into pod details", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "milli-cores", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels.pod}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels.pod}" + } + ], + "mappings": [ + { + "options": { + "match": "null+nan", + "result": { + "color": "transparent", + "index": 0 + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Overall" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 45 + }, + "id": 56, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(pod)(\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum by(pod)(rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\"$1\",\"pod\",\"(.*)\") or #,\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") or\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum (rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"pod\",\".Overall\",\"\",\"\") or\r\nvector(0)>0)", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(_)(\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum by(pod)(rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") or\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum (rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\".Overall\",\"\",\"\") or\r\nvector(0)>0)", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "CPU Usage by Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Click on data series to drill down into pod details", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "working bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels.pod}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels.pod}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 45 + }, + "id": 57, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory working bytes\r\nmax by(pod)(\r\nlabel_replace(\r\n sum by(pod)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") \r\n)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory working bytes\r\nmax by(_)(\r\nlabel_replace(\r\n sum by(pod)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") \r\n)", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Memory Usage by Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 53 + }, + "id": 13, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Errors & Logs\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "yellow", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": true + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "yellow" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PodName" + }, + "properties": [ + { + "id": "custom.width", + "value": 300 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Reason" + }, + "properties": [ + { + "id": "custom.width", + "value": 213 + }, + { + "id": "custom.align", + "value": "center" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "Failed": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ] + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "custom.align", + "value": "left" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Count" + }, + "properties": [ + { + "id": "custom.width", + "value": 102 + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "color", + "value": { + "mode": "continuous-BlPu" + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.width", + "value": 200 + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Message" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 55 + }, + "id": 55, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "LastSeen" + } + ] + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "azureLogAnalytics": { + "query": "KubeEvents\r\n| where TimeGenerated > $__timeFrom() and TimeGenerated <= $__timeTo\r\n| where ClusterName == '$cluster'\r\n| where Name matches regex '${component:raw}'\r\n//| order by TimeGenerated desc\r\n| order by LastSeen desc, FirstSeen desc, TimeGenerated desc\r\n| project-rename PodName = Name\r\n| project FirstSeen, LastSeen, Count, PodName, Reason, Message\r\n| take 10", + "resources": [ + "/subscriptions/af342bf1-1ace-41df-902c-47921400551b" + ], + "resultFormat": "table" + }, + "azureMonitor": { + "allowedTimeGrainsMs": [], + "timeGrain": "auto" + }, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "queryType": "Azure Log Analytics", + "refId": "A" + } + ], + "title": "Last 10 Kube Events entries (from $cluster)", + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 63 + }, + "id": 14, + "links": [ + { + "targetBlank": true, + "title": "Open E4K Main page", + "url": "/d/PlYeCP2Vz/e4k-main?${__all_variables}&${__url_time_range}" + } + ], + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   ${component_text}-specific\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "yellow", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PodName" + }, + "properties": [ + { + "id": "custom.width", + "value": 300 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Reason" + }, + "properties": [ + { + "id": "custom.width", + "value": 112 + }, + { + "id": "custom.align", + "value": "center" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "Failed": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ] + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Count" + }, + "properties": [ + { + "id": "custom.width", + "value": 114 + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "color", + "value": { + "mode": "continuous-BlPu" + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.width", + "value": 200 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Message" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ContainerName" + }, + "properties": [ + { + "id": "custom.width", + "value": 193 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "LogMessage" + }, + "properties": [ + { + "id": "custom.width", + "value": 1656 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "LogSource" + }, + "properties": [ + { + "id": "custom.width", + "value": 140 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 65 + }, + "id": 66, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "azureLogAnalytics": { + "query": "ContainerLogV2\r\n| where TimeGenerated >= $__timeFrom() and TimeGenerated <= $__timeTo()\r\n| where _ResourceId contains '$cluster'\r\n| where ContainerName contains \"e4k\"\r\n| order by TimeGenerated desc\r\n| project TimeGenerated, PodName, ContainerName, LogSource, LogMessage\r\n| take 100", + "resources": [ + "/subscriptions/af342bf1-1ace-41df-902c-47921400551b" + ], + "resultFormat": "table" + }, + "azureMonitor": { + "allowedTimeGrainsMs": [], + "timeGrain": "auto" + }, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "queryType": "Azure Log Analytics", + "refId": "A" + } + ], + "title": "Last 100 Log entries (from $cluster)", + "type": "table" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "description": "Defines the service Component this report focuses on.", + "hide": 2, + "name": "component", + "query": "${VAR_COMPONENT}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_COMPONENT}", + "text": "${VAR_COMPONENT}", + "selected": false + }, + "options": [ + { + "value": "${VAR_COMPONENT}", + "text": "${VAR_COMPONENT}", + "selected": false + } + ] + }, + { + "description": "Defines the service Component this report focuses on.", + "hide": 2, + "name": "component_text", + "query": "${VAR_COMPONENT_TEXT}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_COMPONENT_TEXT}", + "text": "${VAR_COMPONENT_TEXT}", + "selected": false + }, + "options": [ + { + "value": "${VAR_COMPONENT_TEXT}", + "text": "${VAR_COMPONENT_TEXT}", + "selected": false + } + ] + }, + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_node_status_condition", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "kube_node_status_condition", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*cluster=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "hide": 0, + "includeAll": true, + "multi": true, + "name": "namespace", + "options": [], + "query": { + "query": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "hide": 2, + "name": "latency_percentile", + "query": "${VAR_LATENCY_PERCENTILE}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_LATENCY_PERCENTILE}", + "text": "${VAR_LATENCY_PERCENTILE}", + "selected": false + }, + "options": [ + { + "value": "${VAR_LATENCY_PERCENTILE}", + "text": "${VAR_LATENCY_PERCENTILE}", + "selected": false + } + ] + }, + { + "auto": true, + "auto_count": 30, + "auto_min": "10s", + "current": { + "selected": false, + "text": "auto", + "value": "$__auto_interval_latency_quantile_range" + }, + "hide": 2, + "name": "latency_quantile_range", + "options": [ + { + "selected": true, + "text": "auto", + "value": "$__auto_interval_latency_quantile_range" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "15m", + "value": "15m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "3h", + "value": "3h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + } + ], + "query": "5m,10m,15m,1h,3h,6h", + "queryValue": "", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + } + ] + }, + "time": { + "from": "now-2d", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "aio-health-service-mq", + "uid": "e2e98c97-7655-44d1-b8f3-5008b7f6ffbb", + "version": 52, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-health-service-opcua-1698853611489.json b/samples/dashboard/grafana-dashboards/aio-health-service-opcua-1698853611489.json new file mode 100644 index 0000000..aa557e6 --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-health-service-opcua-1698853611489.json @@ -0,0 +1,4434 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + }, + { + "name": "DS_AZURE_MONITOR", + "label": "Azure Monitor", + "description": "", + "type": "datasource", + "pluginId": "grafana-azure-monitor-datasource", + "pluginName": "Azure Monitor" + }, + { + "name": "VAR_COMPONENT", + "type": "constant", + "label": "component", + "value": "(^(opc-ua-|edge-application-supervisor).*|.*-opc-ua-.*)", + "description": "" + }, + { + "name": "VAR_COMPONENT_TEXT", + "type": "constant", + "label": "component_text", + "value": "OPC UA Broker", + "description": "" + }, + { + "name": "VAR_BF_PIPELINE4SELFTEST", + "type": "constant", + "label": "bf_pipeline4selftest", + "value": ".*self-test-bluefin-pipeline.*", + "description": "" + }, + { + "name": "VAR_AIO_OPC_LATENCY_THRESHOLD_MS", + "type": "constant", + "label": "aio_opc_latency_threshold_ms", + "value": "5000", + "description": "" + }, + { + "name": "VAR_LATENCY_PERCENTILE", + "type": "constant", + "label": "latency_percentile", + "value": "0.95", + "description": "" + }, + { + "name": "VAR_AIO_OPC_SLO_SR_GOAL", + "type": "constant", + "label": "aio_opc_slo_sr_goal", + "value": "99.999", + "description": "" + }, + { + "name": "VAR_AIO_OPC_SLO_PUBLISH_LATENCY_MS_GOAL", + "type": "constant", + "label": "aio_opc_slo_publish_latency_ms_goal", + "value": "5000", + "description": "" + }, + { + "name": "VAR_AIO_OPC_SLO_CONNECT_LATENCY_MS_GOAL", + "type": "constant", + "label": "aio_opc_slo_connect_latency_ms_goal", + "value": "3000", + "description": "" + }, + { + "name": "VAR_OPC_UA_BROKER_DASHBOARD_PATH", + "type": "constant", + "label": "opc_ua_broker_dashboard_path", + "value": "d/eaee1655-8c82-4b00-9258-5fa05ba16f04/aio-opc-ua-broker-dashboard", + "description": "" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "grafana-azure-monitor-datasource", + "name": "Azure Monitor", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "piechart", + "name": "Pie chart", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "state-timeline", + "name": "State timeline", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 70, + "panels": [], + "title": "Row title", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 8, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n Azure Edge Services - OPC UA Broker Health\n
\n
\n   Scenario Health (SLO/RUM) related to OPC UA Broker\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 4 + }, + "id": 65, + "panels": [], + "title": " ", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 60, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for ${component_text} ${__field.labels._}", + "url": "${__field.labels.url}?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#7f7f7f", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + }, + { + "color": "#7f7f7f", + "value": 404 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "OPC UA Broker SLO Health" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 1 + }, + { + "id": "links" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "^Supervisor.*[^)]$" + }, + "properties": [ + { + "id": "links" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 5 + }, + "id": 62, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.72, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(min(\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(\r\n # Raw Success Rate for MQTT message publishing by app, qos, and opc-ua connector\r\n label_replace(min by(app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_mqtt_message_publishing_duration_count{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\",aio_opc_mqtt_publish_result=\"success\"}[5m:1m])\r\n * 100 / rate(aio_opc_mqtt_message_publishing_duration_count{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_endpoint\",\"(.*)\"))\r\n ,\"_\",\"MQTT Publishing Success Rate\",\"\",\"\")\r\n >= $aio_opc_slo_sr_goal) or\r\n 0 * sgn(\r\n # Raw Success Rate for MQTT message publishing by app, qos, and opc-ua connector\r\n label_replace(min by(app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_mqtt_message_publishing_duration_count{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\",aio_opc_mqtt_publish_result=\"success\"}[5m:1m])\r\n * 100 / rate(aio_opc_mqtt_message_publishing_duration_count{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_endpoint\",\"(.*)\"))\r\n ,\"_\",\"MQTT Publishing Success Rate\",\"\",\"\")\r\n < $aio_opc_slo_sr_goal) or\r\n vector(0)>0\r\n ) or vector(0))\r\n ,\"url\",\"${opc_ua_broker_dashboard_path}\",\"\",\"\")\r\n ,\"_\",\"MQTT Publishing Success Rate\",\"\",\"\") or\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(\r\n label_replace(min by(app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_session_connect_duration_count{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\",aio_opc_connect_result=\"succeeded\"}[5m:1m])\r\n * 100 / rate(aio_opc_session_connect_duration_count{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_endpoint\",\"(.*)\"))\r\n ,\"_\",\"OPC-UA Connect Success Rate\",\"\",\"\")\r\n >= $aio_opc_slo_sr_goal) or\r\n 0 * sgn(\r\n label_replace(min by(app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_session_connect_duration_count{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\",aio_opc_connect_result=\"succeeded\"}[5m:1m])\r\n * 100 / rate(aio_opc_session_connect_duration_count{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_endpoint\",\"(.*)\"))\r\n ,\"_\",\"OPC-UA Connect Success Rate\",\"\",\"\")\r\n < $aio_opc_slo_sr_goal) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"${opc_ua_broker_dashboard_path}\",\"\",\"\")\r\n ,\"_\",\"OPC UA Connect Success Rate\",\"\",\"\") or\r\n\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(\r\n # Raw Latency for MQTT Publishing\r\n label_replace(\r\n histogram_quantile(0.95,sum by(le,app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\",aio_opc_mqtt_publish_result=\"success\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_endpoint\",\"(.*)\")))\r\n ,\"_\",\"MQTT Publishing P95 Latency\",\"\",\"\") \r\n <= $aio_opc_slo_publish_latency_ms_goal) or\r\n 0 * sgn(\r\n # Raw Latency for MQTT Publishing\r\n label_replace(\r\n histogram_quantile(0.95,sum by(le,app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\",aio_opc_mqtt_publish_result=\"success\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_endpoint\",\"(.*)\")))\r\n ,\"_\",\"MQTT Publishing P95 Latency\",\"\",\"\") \r\n > $aio_opc_slo_publish_latency_ms_goal) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"${opc_ua_broker_dashboard_path}\",\"\",\"\")\r\n ,\"_\",\"MQTT Publishing latency\",\"\",\"\") or \r\n\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(\r\n #Raw latency for OPC UA Connect by app and opc-ua connector\r\n label_replace(\r\n histogram_quantile(0.95,sum by(le,app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_session_connect_duration_bucket{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\",aio_opc_connect_result=\"succeeded\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_endpoint\",\"(.*)\")))\r\n ,\"_\",\"OPC-UA Connect P95 Latency\",\"\",\"\")\r\n <= $aio_opc_slo_connect_latency_ms_goal) or\r\n 0 * sgn(\r\n #Raw latency for OPC UA Connect by app and opc-ua connector\r\n label_replace(\r\n histogram_quantile(0.95,sum by(le,app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_session_connect_duration_bucket{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\",aio_opc_connect_result=\"succeeded\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_endpoint\",\"(.*)\")))\r\n ,\"_\",\"OPC-UA Connect P95 Latency\",\"\",\"\")\r\n > $aio_opc_slo_connect_latency_ms_goal) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"${opc_ua_broker_dashboard_path}\",\"\",\"\")\r\n ,\"_\",\"OPC-UA Connect latency\",\"\",\"\") or \r\n vector(0)>0\r\n),\"_\",\"OPC UA Broker SLO Health\",\"\",\"\")", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#label_replace(min(\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(\r\n # Raw Success Rate for MQTT message publishing by app, qos, and opc-ua connector\r\n label_replace(min by(app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_mqtt_message_publishing_duration_count{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\",aio_opc_mqtt_publish_result=\"success\"}[5m:1m])\r\n * 100 / rate(aio_opc_mqtt_message_publishing_duration_count{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_endpoint\",\"(.*)\"))\r\n ,\"_\",\"MQTT Publishing Success Rate\",\"\",\"\")\r\n >= $aio_opc_slo_sr_goal) or\r\n 0 * sgn(\r\n # Raw Success Rate for MQTT message publishing by app, qos, and opc-ua connector\r\n label_replace(min by(app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_mqtt_message_publishing_duration_count{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\",aio_opc_mqtt_publish_result=\"success\"}[5m:1m])\r\n * 100 / rate(aio_opc_mqtt_message_publishing_duration_count{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_endpoint\",\"(.*)\"))\r\n ,\"_\",\"MQTT Publishing Success Rate\",\"\",\"\")\r\n < $aio_opc_slo_sr_goal) or\r\n vector(0)>0\r\n ) or vector(0))\r\n ,\"url\",\"${opc_ua_broker_dashboard_path}\",\"\",\"\")\r\n ,\"_\",\"MQTT Publishing Success Rate\",\"\",\"\") or\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(\r\n label_replace(min by(app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_session_connect_duration_count{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\",aio_opc_connect_result=\"succeeded\"}[5m:1m])\r\n * 100 / rate(aio_opc_session_connect_duration_count{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_endpoint\",\"(.*)\"))\r\n ,\"_\",\"OPC-UA Connect Success Rate\",\"\",\"\")\r\n >= $aio_opc_slo_sr_goal) or\r\n 0 * sgn(\r\n label_replace(min by(app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_session_connect_duration_count{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\",aio_opc_connect_result=\"succeeded\"}[5m:1m])\r\n * 100 / rate(aio_opc_session_connect_duration_count{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_endpoint\",\"(.*)\"))\r\n ,\"_\",\"OPC-UA Connect Success Rate\",\"\",\"\")\r\n < $aio_opc_slo_sr_goal) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"${opc_ua_broker_dashboard_path}\",\"\",\"\")\r\n ,\"_\",\"OPC UA Connect Success Rate\",\"\",\"\") or\r\n\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(\r\n # Raw Latency for MQTT Publishing\r\n label_replace(\r\n histogram_quantile(0.95,sum by(le,app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\",aio_opc_mqtt_publish_result=\"success\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_endpoint\",\"(.*)\")))\r\n ,\"_\",\"MQTT Publishing P95 Latency\",\"\",\"\") \r\n <= $aio_opc_slo_publish_latency_ms_goal) or\r\n 0 * sgn(\r\n # Raw Latency for MQTT Publishing\r\n label_replace(\r\n histogram_quantile(0.95,sum by(le,app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\",aio_opc_mqtt_publish_result=\"success\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_endpoint\",\"(.*)\")))\r\n ,\"_\",\"MQTT Publishing P95 Latency\",\"\",\"\") \r\n > $aio_opc_slo_publish_latency_ms_goal) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"${opc_ua_broker_dashboard_path}\",\"\",\"\")\r\n ,\"_\",\"MQTT Publishing latency\",\"\",\"\") or \r\n\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(\r\n #Raw latency for OPC UA Connect by app and opc-ua connector\r\n label_replace(\r\n histogram_quantile(0.95,sum by(le,app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_session_connect_duration_bucket{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\",aio_opc_connect_result=\"succeeded\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_endpoint\",\"(.*)\")))\r\n ,\"_\",\"OPC-UA Connect P95 Latency\",\"\",\"\")\r\n <= $aio_opc_slo_connect_latency_ms_goal) or\r\n 0 * sgn(\r\n #Raw latency for OPC UA Connect by app and opc-ua connector\r\n label_replace(\r\n histogram_quantile(0.95,sum by(le,app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_session_connect_duration_bucket{cluster=\"$cluster\",aio_opc_connector_schema=\"opc.tcp\",aio_opc_connect_result=\"succeeded\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_endpoint\",\"(.*)\")))\r\n ,\"_\",\"OPC-UA Connect P95 Latency\",\"\",\"\")\r\n > $aio_opc_slo_connect_latency_ms_goal) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"${opc_ua_broker_dashboard_path}\",\"\",\"\")\r\n ,\"_\",\"OPC-UA Connect latency\",\"\",\"\") or \r\n vector(0)>0\r\n#),\"_\",\"OPC UA Broker SLO Health\",\"\",\"\")", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "B" + } + ], + "title": "Service Level Objectives", + "transformations": [], + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".*Latency[\"].*" + }, + "properties": [ + { + "id": "min" + }, + { + "id": "max" + }, + { + "id": "unit", + "value": "ms" + }, + { + "id": "custom.axisLabel", + "value": "Latency" + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.scaleDistribution", + "value": { + "log": 10, + "type": "symlog" + } + }, + { + "id": "custom.axisGridShow", + "value": false + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*Success Rate[\"].*" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisSoftMin", + "value": -1 + }, + { + "id": "custom.axisSoftMax", + "value": 101 + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.axisLabel", + "value": "Success Rate" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hide Me" + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "{_=\"Hide Me\"}" + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 5 + }, + "id": 63, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Hidden series (to avoid 'No data' message)\r\nlabel_replace(vector(0), \"_\",\"Hide Me\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "Z" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Raw Success Rate for MQTT message publishing by app and opc-ua connector\r\nlabel_replace(min by(app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_mqtt_message_publishing_duration_count{cluster=\"$cluster\",aio_opc_module_type=\"opc-ua-connector\",aio_opc_mqtt_publish_result=\"success\"}[5m:1m])\r\n * 100 / rate(aio_opc_mqtt_message_publishing_duration_count{cluster=\"$cluster\",aio_opc_module_type=\"opc-ua-connector\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_module_name\",\"(.*)\"))\r\n,\"_\",\"MQTT Publishing Success Rate\",\"\",\"\") < $aio_opc_slo_sr_goal", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#Raw latency for MQTT message publishing by app and opc-ua connector\r\nlabel_replace(\r\n histogram_quantile(0.95,sum by(le,app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",aio_opc_module_type=\"opc-ua-connector\",aio_opc_mqtt_publish_result=\"success\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_module_name\",\"(.*)\")))\r\n,\"_\",\"MQTT Publishing P95 Latency\",\"\",\"\") > $aio_opc_slo_publish_latency_ms_goal", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#Raw latency for OPC UA Connect by app and opc-ua connector\r\nlabel_replace(\r\n histogram_quantile(0.95,sum by(le,app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_session_connect_duration_bucket{cluster=\"$cluster\",aio_opc_module_type=\"opc-ua-connector\",aio_opc_connect_result=\"succeeded\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_module_name\",\"(.*)\")))\r\n,\"_\",\"OPC-UA Connect P95 Latency\",\"\",\"\") > $aio_opc_slo_connect_latency_ms_goal", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Raw Success Rate for OPC Session Connect by app and opc-ua connector\r\nlabel_replace(min by(app,opc_ua_connector)(label_replace(label_replace(\r\n rate(aio_opc_session_connect_duration_count{cluster=\"$cluster\",aio_opc_module_type=\"opc-ua-connector\",aio_opc_connect_result=\"succeeded\"}[5m:1m])\r\n * 100 / rate(aio_opc_session_connect_duration_count{cluster=\"$cluster\",aio_opc_module_type=\"opc-ua-connector\"}[5m:1m])\r\n ,\"app\",\"$1\",\"aio_opc_application\",\"(.*)\")\r\n ,\"opc_ua_connector\",\"$1\",\"aio_opc_module_name\",\"(.*)\"))\r\n,\"_\",\"OPC-UA Connect Success Rate\",\"\",\"\") < $aio_opc_slo_sr_goal", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "SLO Unhealthy Details (Goals: Success Rate >= $aio_opc_slo_sr_goal%, Connect Latency <= ${aio_opc_slo_connect_latency_ms_goal}ms, Publish Latency <=${aio_opc_slo_publish_latency_ms_goal}ms))", + "type": "timeseries" + }, + { + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 64, + "title": " ", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 10, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Service Health (Synthetics/Self-test)\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 60, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for ${component_text} ${__field.labels._}", + "url": "${__field.labels.url}?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#7f7f7f", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + }, + { + "color": "#7f7f7f", + "value": 404 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "E4I Overall Health" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 1 + }, + { + "id": "links" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 16 + }, + "id": 16, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.72, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(min(\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(\r\n 100*sum(rate(aio_opc_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\",aio_opc_mqtt_publish_result=\"Success\"}[$__rate_interval]))\r\n / sum(rate(aio_opc_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\"}[$__rate_interval]))\r\n > 99) or\r\n 0 * sgn(sum(rate(aio_opc_mqtt_message_publishing_duration_count{cluster=\"$cluster\",service_name=\"supervisor\"}[$__rate_interval])) > 0) or\r\n vector(0)>0\r\n ) or vector(0))\r\n ,\"url\",\"${opc_ua_broker_dashboard_path}\",\"\",\"\")\r\n ,\"_\",\"Supervisor Success Rate\",\"\",\"\") or\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_opc_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n ))) < $aio_opc_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_opc_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n ))) >= $aio_opc_latency_threshold_ms) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"${opc_ua_broker_dashboard_path}\",\"\",\"\")\r\n ,\"_\",\"Supervisor latency\",\"\",\"\") or \r\n vector(0)>0\r\n),\"_\",\"OPC UA Broker Overall Health\",\"\",\"\")", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#label_replace(min(\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(\r\n 100*sum(rate(aio_opc_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\",aio_opc_mqtt_publish_result=\"Success\"}[$__rate_interval]))\r\n / sum(rate(aio_opc_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\"}[$__rate_interval]))\r\n > 99) or\r\n 0 * sgn(sum(rate(aio_opc_mqtt_message_publishing_duration_count{cluster=\"$cluster\",service_name=\"supervisor\"}[$__rate_interval])) > 0) or\r\n vector(0)>0\r\n ) or vector(0))\r\n ,\"url\",\"${opc_ua_broker_dashboard_path}\",\"\",\"\")\r\n ,\"_\",\"Supervisor Success Rate\",\"\",\"\") or\r\n label_replace(label_replace(\r\n (min(\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_opc_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n ))) < $aio_opc_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_opc_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n ))) >= $aio_opc_latency_threshold_ms) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"url\",\"${opc_ua_broker_dashboard_path}\",\"\",\"\")\r\n ,\"_\",\"Supervisor latency\",\"\",\"\") or \r\n vector(0)>0\r\n#),\"_\",\"OPC UA Broker Overall Health\",\"\",\"\")", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "B" + } + ], + "title": "Service Health", + "transformations": [], + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Click for Bluefin details", + "url": "/d/e57b7777-71be-43a8-87bd-d917391b154f/bluefin-overview?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 0.8 + }, + { + "color": "dark-green", + "value": 1 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Supervisor errors" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "line" + }, + { + "id": "custom.lineWidth", + "value": 3 + }, + { + "id": "custom.fillOpacity", + "value": 5 + }, + { + "id": "custom.pointSize", + "value": 5 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 0, + 5 + ], + "fill": "dot" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisLabel", + "value": "Error counts" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Supervisor Success Rate" + }, + "properties": [ + { + "id": "custom.axisSoftMax" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "0": { + "color": "#808080", + "index": 0 + } + }, + "type": "value" + } + ] + }, + { + "id": "max", + "value": 101 + }, + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 16 + }, + "id": 28, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "asc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n 100*sum(rate(aio_opc_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\",aio_opc_mqtt_publish_result=\"Success\"}[$__rate_interval]))\r\n / sum(rate(aio_opc_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\"}[$__rate_interval]))\r\n ,\"_\",\"Supervisor Success Rate\",\"\",\"\") or\r\nlabel_replace(\r\n 60*sum(rate(aio_opc_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\",aio_opc_mqtt_publish_result!=\"Success\"}[$__rate_interval]))\r\n# #0 * sgn(\r\n# round(sum(increase(stage_errors{cluster=~\"$cluster\",cloud_resource_id=~\"$bf_pipeline4selftest\"}[$__rate_interval])))#) or\r\n# #or vector(3)\r\n ,\"_\",\"Supervisor errors\",\"\",\"\") or\r\n vector(0)>0", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Supervisor Output and Errors", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Click for Bluefin details", + "url": "/d/e57b7777-71be-43a8-87bd-d917391b154f/bluefin-overview?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "hidden-timeline" + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Self-test latency threshold" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Self-test pipeline latency over threshold" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.lineWidth", + "value": 3 + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 20 + }, + "id": 29, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n max(histogram_quantile(0.95, rate(\r\n aio_opc_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n ))) #< $aio_opc_latency_threshold_ms#) or\r\n ,\"_\",\"Self-test pipeline latency\",\"\",\"\") or\r\nlabel_replace($aio_opc_latency_threshold_ms * sgn(\r\n max(histogram_quantile(0.95, rate(\r\n aio_opc_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n ))) #< $aio_opc_latency_threshold_ms#) or\r\n ),\"_\",\"Self-test latency threshold\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n max(histogram_quantile(0.95, rate(\r\n aio_opc_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n ))) >= $aio_opc_latency_threshold_ms#) or\r\n ,\"x\",\"Over threshold\",\"\",\"\")\r\n ,\"_\",\"Self-test pipeline latency over threshold\",\"\",\"\") or\r\nlabel_replace(vector(0),\"_\",\"hidden-timeline\",\"\",\"\") or\r\nvector(0)>0", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + } + ], + "title": "Supervisor Latency", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 24 + }, + "id": 12, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Golden Metrics\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [ + { + "options": { + "match": "null+nan", + "result": { + "color": "transparent", + "index": 0 + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".*s$" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisLabel", + "value": "total count" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*[/]sec[)]$" + }, + "properties": [ + { + "id": "custom.axisLabel", + "value": "throughput (msgs/sec)" + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 26 + }, + "id": 50, + "links": [ + { + "targetBlank": true, + "title": "Show details on OPC UA Broker Dashboard", + "url": "${opc_ua_broker_dashboard_path}?${__all_variables}&${__url_time_range}" + } + ], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#label_replace(#quantile_over_time($latency_percentile,\r\n# sum(rate(reader_incoming_messages{cluster=\"$cluster\"}[$__rate_interval]))\r\n# #[$latency_quantile_range:])\r\n# ,\"_\",\"Input (msgs/sec)\",\"\",\"\") or\r\nlabel_replace(#quantile_over_time($latency_percentile,\r\n sum(rate(aio_opc_message_egress_count{cluster=\"$cluster\"}[$__rate_interval])) # includes housekeeping as well as asset telemetry\r\n #[$latency_quantile_range:])\r\n ,\"_\",\"Output (msgs/sec)\",\"\",\"\") or\r\nlabel_replace(\r\n sum(aio_opc_endpoint_count{cluster=\"$cluster\"})\r\n ,\"_\",\"Endpoints (count)\",\"\",\"\") or\r\nlabel_replace(\r\n sum(aio_opc_asset_count{cluster=\"$cluster\"})\r\n ,\"_\",\"Assets (count)\",\"\",\"\") or\r\nlabel_replace(\r\n sum(rate(aio_opc_asset_telemetry_data_change_count{cluster=\"$cluster\"}[$__rate_interval]))\r\n ,\"_\",\"Data Changes Inbound (Publish Responses/sec)\",\"\",\"\") or\r\n# label_replace(vector(1),\"_\",\"TODO: Usage/Volume\",\"\",\"\") or\r\nvector(0) > 0", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Usage/Volume", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Success Rate" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 4 + }, + { + "id": "custom.axisSoftMin", + "value": 0 + }, + { + "id": "custom.axisSoftMax", + "value": 101 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*(Errors)$" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "unit", + "value": "none" + }, + { + "id": "custom.axisLabel", + "value": "Error Count" + }, + { + "id": "custom.drawStyle", + "value": "bars" + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "custom.axisSoftMin", + "value": 0 + }, + { + "id": "custom.axisSoftMax", + "value": 20 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 26 + }, + "id": 51, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n ( (sum(rate(aio_opc_asset_data_change_value_change_count{cluster=\"$cluster\"}[$__rate_interval])) > 0 or vector(0))\r\n - (sum(rate(aio_opc_asset_data_change_bad_value_change_count{cluster=\"$cluster\"}[$__rate_interval])) > 0 or vector(0))\r\n ) / (\r\n (sum(rate(aio_opc_asset_data_change_value_change_count{cluster=\"$cluster\"}[$__rate_interval])) > 0)\r\n ),\"_\",\".Success Rate\",\"\",\"\") * 100 or\r\nlabel_replace(\r\n sum(60*rate(aio_opc_runtime_error_count{cluster=\"$cluster\"}[$__rate_interval])) or vector(0)\r\n ,\"_\",\"Runtime Errors\",\"\",\"\") or\r\n#label_replace(vector(1),\"_\",\"TODO: Success Rate\",\"\",\"\") or\r\nvector(0) > 0", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Success Rate/Errors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "Self-test.*" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 0, + 10 + ], + "fill": "dot" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 26 + }, + "id": 52, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#ping_latency_last_value_ms{cluster=\"$cluster\"} or\r\nmax by (_)(\r\n label_replace(label_replace(label_replace(#quantile_over_time($latency_percentile,\r\n histogram_quantile($latency_percentile, sum(rate(aio_opc_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\"}[$latency_quantile_range])) by (le))\r\n #[$latency_quantile_range:])\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"MQTT Message Publishing Latency $1\",\"pout\",\"(.*)\") or\r\n label_replace(label_replace(label_replace(#quantile_over_time($latency_percentile,\r\n histogram_quantile($latency_percentile, rate(aio_opc_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\"}[$latency_quantile_range]))\r\n #[$latency_quantile_range:])\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"MQTT Message Publishing Latency $1 (worst)\",\"pout\",\"(.*)\") or\r\n label_replace(label_replace(label_replace(#quantile_over_time($latency_percentile,\r\n histogram_quantile($latency_percentile, sum(rate(aio_opc_data_change_processing_duration_bucket{cluster=\"$cluster\"}[$latency_quantile_range])) by (le))\r\n #[$latency_quantile_range:])\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"OPC Data Change Processing Latency $1\",\"pout\",\"(.*)\") or\r\n label_replace(label_replace(label_replace(#quantile_over_time($latency_percentile,\r\n histogram_quantile($latency_percentile, rate(aio_opc_data_change_processing_duration_bucket{cluster=\"$cluster\"}[$latency_quantile_range]))\r\n #[$latency_quantile_range:])\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"OPC Data Change Processing Latency $1 (worst)\",\"pout\",\"(.*)\") or\r\n vector(0)>0) or\r\n#label_replace(vector(1),\"_\",\"TODO: Latency\",\"\",\"\") or\r\nvector(0)>0", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(histogram_quantile(0.95, rate(pipeline_latency_bucket{cluster=~\"$cluster|int-virtual-02\",cloud_resource_id=~\".*self-test-bluefin-pipeline.*\"}[$__rate_interval])),\"_\",\"P95\",\"\",\"\") or\r\nvector(0)>0", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMax": 15, + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Backpressure Rejection %" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 3 + }, + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "# rejected by .*" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "bars" + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisLabel", + "value": "Packet Rejected Count" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 26 + }, + "id": 53, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n max(aio_opc_output_queue_count{cluster=~\"$cluster\"}) #by(aio_opc_module_name)# without(application,cluster,aio_opc_application,aio_opc_module_name,aio_opc_module_type,exported_job,instance,job,module_type,module_name,service_name,service_version,telemetry_sdk_language,telemetry_sdk_name, telemetry_sdk_version,service_namespace)\r\n ,\"_\",\"Max Output Queue Count\",\"\",\"\") or\r\nlabel_replace(\r\n sum by()(#aio_opc_module_name) (\r\n rate(aio_opc_asset_data_change_local_override_count{cluster=~\"$cluster\",aio_opc_module_type=\"opc-ua-connector\"}[$__rate_interval])# > 0\r\n ),\"_\",\"Server Queue Overflow Rate\",\"\",\"\") or\r\n#label_replace(vector(0),\"_\",\"TODO: Saturation\",\"\",\"\") or\r\nvector(0)>0", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Saturation", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 11, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Infrastructure Workload Health\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "Click for more details", + "url": "/d/eef9bf1c-b27a-4e86-a7f0-2a39cdfbeeca/health-infrastructure?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red" + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 36 + }, + "id": 31, + "links": [ + { + "targetBlank": true, + "title": "See infra workload health for all components", + "url": "/d/E5cCeHj4z/health-infra-workload?${cluster:queryparam}&${__url_time_range}" + } + ], + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.9, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Workload Readiness health\r\n############################\r\nlabel_replace(min(\r\navg(label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n label_replace(label_join(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n / label_replace(label_join(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n) by (workload) >=0 \r\n) or vector(0),\"_\",\"Workload Readiness\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Restart Health:\r\n############################\r\nlabel_replace(\r\n sgn(sum_over_time(sum(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[10m:1m]\r\n )*60)[1h:]) > 5) * 0.0 # RED: Cumulative restarts over X(5) time greater than Y(1h)\r\n or (max(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[5m:1m]\r\n )*60*5) > 0) * 0.5 # YELLOW: restarts detected but below Red threshold\r\n or sgn(max(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}\r\n + 1 >= 0))\r\n #or vector(1) # Healthy\r\n ,\"_\",\"Container Restart Health\",\"\",\"\")\r\n## uncomment below to t-shoot this health metric\r\n# or label_replace(sum_over_time(sum(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[10m:1m])*60)[1h:]),\"_\",\"Total-restarts-over-time\",\"\",\"\")\r\n# or label_replace((max(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[5m:1m])*60*5) without (__name__,uid,instance,job) > 0),\"_\",\"restart\",\"\",\"\") # Base query for counting restarts\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container CPU top-level health\r\n################################\r\nlabel_replace(\r\nmin(sgn( # Check for throttling > N indicating container is exceeding its CPU limits\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m]) \r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m])\r\n >= 0.60) # If throttle create is greater than this percentage, we'll multiply sgn by 0.5 to show as error (or warning depending on threshold coloring)\r\n ) # by (namespace,container) # These are commented out for top-level\r\n * 0.0\r\nor\r\nmin(sgn( # Check for throttling > N indicating container is exceeding its CPU limits\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m]) \r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m])\r\n >= 0.40) # If throttle create is greater than this percentage, we'll multiply sgn by 0.5 to show as error (or warning depending on threshold coloring)\r\n ) # by (namespace,container) # These are commented out for top-level\r\n * 0.5\r\nor\r\nmin( # Check to see if container is missing CPU Limits configuration\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"cpu\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n ) #by (namespace,container) # These are commented out for top-level\r\n,\"_\",\"Container CPU Health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Memory Health:\r\n###########################\r\nlabel_replace(\r\nmin( # Look for high memory utilization\r\n sgn((\r\n max(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container)\r\n / min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"memory\",pod=~\"${component:raw}\"}) by (namespace, container)\r\n ) >= .95) - 0.5 # show health state of 0.5 if container memory utilization >= 95%\r\n) #by (container) \r\nor\r\nmin( # Look for missing limits which we will show as 0 if missing\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"memory\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n) #by (container) \r\n,\"_\",\"Container Memory health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Health Summary", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "max(rate(container_cpu_usage_seconds_total{namespace=~\"alice-springs|symphony-k8s-system\",container=\"\",cpu=\"total\"}[5m])*300 > 0) ": "POD CPU (max)", + "min( # Workload ready percents (for deployment, daemonset, replicaset, and statefulset)\r\n label_replace(label_join(\r\n {job=\"kube-state-metrics\",namespace=~\"alice-springs|symphony-k8s-system\",\r\n __name__=~\"kube_(deployment|daemonset|replicaset|statefulset)_status_(replicas_ready|ready_replicas|number_ready)\"}\r\n ,\"workload\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n / label_replace(label_join(\r\n {job=\"kube-state-metrics\",namespace=~\"alice-springs|symphony-k8s-system\",\r\n __name__=~\"kube_(deployment|daemonset|replicaset|statefulset)_status_(replicas|desired_number_scheduled)\"}\r\n ,\"workload\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n) #by (workloadType) #namespace) #, workloadType) #, workload)": "Workload ready health" + } + } + } + ], + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red" + }, + { + "color": "green", + "value": 20 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 6, + "y": 36 + }, + "id": 33, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(sum ( # by(workloadType) (\r\n#min(\r\n# label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n label_replace(label_join(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n),\"_\",\"Ready\",\"\",\"\")\r\n# / label_replace(label_join(\r\n# kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\"$namespace\",daemonset=~\"${component:raw}\"} or\r\n# kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\"$namespace\",deployment=~\"${component:raw}\"} or\r\n# kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\"$namespace\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n# ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n#) by (workload) >=0 ", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#min(\r\n# label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n# label_replace(label_join(\r\n# kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",deployment=~\"${component:raw}\"} or\r\n# kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",daemonset=~\"${component:raw}\"} or\r\n# kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n# / label_replace(label_join(\r\n label_replace(sum(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n ),\"_\",\"Requested\",\"\",\"\")\r\n# ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n#) by (workload) >=0 ", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Workloads", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 8, + "y": 36 + }, + "id": 35, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor label_replace(vector(0),\"status\",\"Ready\",\"\",\"\")\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "DaemonSets", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 10, + "y": 36 + }, + "id": 37, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor label_replace(vector(0),\"status\",\"Ready\",\"\",\"\") # this is to zero if no workloads of this type exist\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "Deployments", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 12, + "y": 36 + }, + "id": 39, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor \r\nlabel_replace(vector(0),\"status\",\"Ready\",\"\",\"\")\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "StatefulSets", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 1 + }, + { + "color": "dark-orange", + "value": 5 + }, + { + "color": "red", + "value": 10 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 14, + "y": 36 + }, + "id": 41, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Container Restarts\r\nlabel_replace(ceil(sum_over_time(sum(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[10m:1m])*60)[1h:])),\"_\",\"restarts\",\"\",\"\")\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "#EAB839", + "value": 40 + }, + { + "color": "red", + "value": 60 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percent containers with CPU Limits (%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "super-light-purple", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Usage (milli-cores)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisColorMode", + "value": "series" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Max Throttled (%)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "thresholds", + "seriesBy": "max" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 36 + }, + "id": 59, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\n(label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))*1000,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\") )\r\n# Percent of containers with limits defined\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"Percent containers with CPU Limits (%)\",\"\",\"\")\r\n# CPU Throttling:\r\nor label_replace(100*(max(\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n )),\"_\",\"CPU Max Throttled (%)\",\"\",\"\")\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(quantile_over_time(0.95,sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\nvector(0)>0\r\n# Sum of all limits defined, in Cores\r\nor label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# WIP:\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"WIP-PERCENT_WITH_LIMITS\",\"\",\"\")\r\nor label_replace(count(\r\n kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"})\r\n ,\"_\",\"WIP-NUMERATOR\",\"\",\"\")\r\nor label_replace(count(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) #without(cluster,container,cpu,id,image,instance,job,name,namespace,pod)\r\n ,\"_\",\"WIP-DENOMINATOR\",\"\",\"\")\r\n# ", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "CPU", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "#EAB839", + "value": 80 + }, + { + "color": "orange", + "value": 85 + }, + { + "color": "red", + "value": 90 + }, + { + "color": "dark-red", + "value": 95 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percent containers with Memory Limits (%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mem Working Bytes (MB)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisColorMode", + "value": "series" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mem Max Usage vs Limit (%)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "thresholds", + "seriesBy": "max" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 36 + }, + "id": 61, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory Usage (MB version)\r\n(label_replace(sum(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"Mem Working Bytes (MB)\",\"\",\"\") )\r\n# Percent containers with limits\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"memory\"}) /\r\n count(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}) *100\r\n ,\"_\",\"Percent containers with Memory Limits (%)\",\"\",\"\")\r\n# Max Mem % Usage:\r\nor label_replace(100*(max(\r\n max_over_time((max by(container)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}))[10m:])\r\n / max by(container)(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"memory\"})\r\n )),\"_\",\"Mem Max Usage vs Limit (%)\",\"\",\"\")\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(quantile_over_time(0.95,sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\nvector(0)>0\r\n# Sum of all limits defined, in Cores\r\nor label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# WIP:\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"WIP-PERCENT_WITH_LIMITS\",\"\",\"\")\r\nor label_replace(count(\r\n kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"})\r\n ,\"_\",\"WIP-NUMERATOR\",\"\",\"\")\r\nor label_replace(count(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) #without(cluster,container,cpu,id,image,instance,job,name,namespace,pod)\r\n ,\"_\",\"WIP-DENOMINATOR\",\"\",\"\")\r\n# ", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "milli-cores", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels._}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels._}.*" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Overall" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "number" + }, + "properties": [ + { + "id": "links" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 40 + }, + "id": 47, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(_)(\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum by(pod)(rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") or\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum (rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\".Overall\",\"\",\"\") or\r\nvector(0)>0)", + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + } + ], + "title": "CPU Usage by Workload", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "working bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels._}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels._}.*" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byType", + "options": "number" + }, + "properties": [ + { + "id": "links" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 40 + }, + "id": 48, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(_)(\r\nlabel_replace(\r\n sum by(pod)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") \r\n)\r\n##(label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))*1000,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\") )\r\n## and label_replace(max_over_time(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))[3d:]) < 0.2,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\")) # Show milli-cores if rate below 0.2 cores\r\n# CPU Time (cores version, if >= 0.2 cores)\r\n##or (label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval])),\"_\",\"CPU Usage (cores)\",\"\",\"\") \r\n## and label_replace(max_over_time(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))[3d:]) >= 0.2,\"_\",\"CPU Usage (cores)\",\"\",\"\")) # Show in cores if rate at or above 0.2 cores\r\n# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(max_over_time(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\n# Sum of all limits defined, in Cores\r\n##or label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# CPU Throttling:\r\n##or label_replace(100*(max(\r\n## rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n## / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n## )),\"_\",\"CPU Max Throttled (%)\",\"\",\"\")\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Memory Usage by Workload", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Click on data series to drill down into pod details", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "milli-cores", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels.pod}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels.pod}" + } + ], + "mappings": [ + { + "options": { + "match": "null+nan", + "result": { + "color": "transparent", + "index": 0 + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Overall" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 48 + }, + "id": 56, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(pod)(\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum by(pod)(rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\"$1\",\"pod\",\"(.*)\") or #,\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") or\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum (rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"pod\",\".Overall\",\"\",\"\") or\r\nvector(0)>0)", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(_)(\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum by(pod)(rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") or\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum (rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\".Overall\",\"\",\"\") or\r\nvector(0)>0)", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "CPU Usage by Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Click on data series to drill down into pod details", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "working bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels.pod}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels.pod}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 48 + }, + "id": 57, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory working bytes\r\nmax by(pod)(\r\nlabel_replace(\r\n sum by(pod)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") \r\n)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory working bytes\r\nmax by(_)(\r\nlabel_replace(\r\n sum by(pod)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") \r\n)", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Memory Usage by Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 56 + }, + "id": 13, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Errors & Logs\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "yellow", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PodName" + }, + "properties": [ + { + "id": "custom.width", + "value": 300 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Reason" + }, + "properties": [ + { + "id": "custom.width", + "value": 112 + }, + { + "id": "custom.align", + "value": "center" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "Failed": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ] + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Count" + }, + "properties": [ + { + "id": "custom.width", + "value": 114 + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "color", + "value": { + "mode": "continuous-BlPu" + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.width", + "value": 200 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Message" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 58 + }, + "id": 55, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "LastSeen" + } + ] + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "azureLogAnalytics": { + "query": "KubeEvents\r\n| where TimeGenerated >= $__timeFrom() and TimeGenerated <= $__timeTo()\r\n| where ClusterName == '$cluster'\r\n| where Name matches regex '${component:raw}'\r\n//| order by TimeGenerated desc\r\n| order by LastSeen desc, FirstSeen desc, TimeGenerated desc\r\n| project-rename PodName = Name\r\n| project FirstSeen, LastSeen, Count, PodName, Reason, Message\r\n| take 10", + "resources": [ + "/subscriptions/af342bf1-1ace-41df-902c-47921400551b" + ], + "resultFormat": "table" + }, + "azureMonitor": { + "allowedTimeGrainsMs": [], + "timeGrain": "auto" + }, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "queryType": "Azure Log Analytics", + "refId": "A" + } + ], + "title": "Last 10 Kube Events entries (from $cluster)", + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 66 + }, + "id": 14, + "links": [ + { + "targetBlank": true, + "title": "Open ${component_text} - Overview page", + "url": "/d/e57b7777-71be-43a8-87bd-d917391b154f/bluefin-overview?${__all_variables}&${__url_time_range}" + } + ], + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   ${component_text}-specific\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "yellow", + "mode": "fixed" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 2, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [ + { + "options": { + "_stderr": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "_ stderr" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 15 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 68 + }, + "id": 67, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.5.8", + "targets": [ + { + "azureLogAnalytics": { + "query": "ContainerLogV2\r\n| where TimeGenerated >= $__timeFrom() and TimeGenerated <= $__timeTo()\r\n| where _ResourceId contains '$cluster'\r\n| where ContainerName matches regex '(^(opc-ua-|edge-application-supervisor).*|.*-opc-ua-.*)'\r\n| summarize _=count() by LogSource, bin(TimeGenerated, 1m)\r\n| order by TimeGenerated asc\r\n", + "resources": [ + "/subscriptions/af342bf1-1ace-41df-902c-47921400551b" + ], + "resultFormat": "time_series" + }, + "azureMonitor": { + "allowedTimeGrainsMs": [], + "timeGrain": "auto" + }, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "queryType": "Azure Log Analytics", + "refId": "A" + } + ], + "title": "Count of Log Entries by STDERR and STDOUT (cluster: $cluster)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": {} + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "yellow", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PodName" + }, + "properties": [ + { + "id": "custom.width", + "value": 386 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.width", + "value": 200 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ContainerName" + }, + "properties": [ + { + "id": "custom.width", + "value": 302 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "LogMessage" + }, + "properties": [ + { + "id": "custom.width", + "value": 1656 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "LogSource" + }, + "properties": [ + { + "id": "custom.width", + "value": 140 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 15, + "w": 24, + "x": 0, + "y": 76 + }, + "id": 69, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "9.5.8", + "targets": [ + { + "azureLogAnalytics": { + "query": "ContainerLogV2\r\n| where TimeGenerated >= $__timeFrom() and TimeGenerated <= $__timeTo()\r\n| where _ResourceId contains '$cluster'\r\n| where ContainerName matches regex '(^(opc-ua-|edge-application-supervisor).*|.*-opc-ua-.*)'\r\n| where LogSource == 'stdout'\r\n| where LogMessage startswith '<4>'\r\n| order by TimeGenerated desc\r\n| project TimeGenerated, PodName, ContainerName, LogSource, LogMessage\r\n| take 100", + "resources": [ + "/subscriptions/af342bf1-1ace-41df-902c-47921400551b" + ], + "resultFormat": "table" + }, + "azureMonitor": { + "allowedTimeGrainsMs": [], + "timeGrain": "auto" + }, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "queryType": "Azure Log Analytics", + "refId": "A" + } + ], + "title": "Error Logs - Last 100 Container Logs entries with severity 'error' (cluster: $cluster)", + "type": "table" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 91 + }, + "id": 71, + "panels": [ + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "yellow", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PodName" + }, + "properties": [ + { + "id": "custom.width", + "value": 386 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.width", + "value": 200 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ContainerName" + }, + "properties": [ + { + "id": "custom.width", + "value": 302 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "LogMessage" + }, + "properties": [ + { + "id": "custom.width", + "value": 1656 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "LogSource" + }, + "properties": [ + { + "id": "custom.width", + "value": 140 + }, + { + "id": "color", + "value": { + "fixedColor": "dark-yellow", + "mode": "fixed" + } + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + } + ] + }, + "gridPos": { + "h": 18, + "w": 24, + "x": 0, + "y": 92 + }, + "id": 68, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "9.5.8", + "targets": [ + { + "azureLogAnalytics": { + "query": "ContainerLogV2\r\n| where TimeGenerated >= $__timeFrom() and TimeGenerated <= $__timeTo()\r\n| where _ResourceId contains '$cluster'\r\n| where ContainerName matches regex '(^(opc-ua-|edge-application-supervisor).*|.*-opc-ua-.*)'\r\n| where LogSource == 'stdout'\r\n| order by TimeGenerated desc\r\n| project TimeGenerated, PodName, ContainerName, LogSource, LogMessage\r\n| take 100", + "resources": [ + "/subscriptions/af342bf1-1ace-41df-902c-47921400551b" + ], + "resultFormat": "table" + }, + "azureMonitor": { + "allowedTimeGrainsMs": [], + "timeGrain": "auto" + }, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "queryType": "Azure Log Analytics", + "refId": "A" + } + ], + "title": "Verbose Logs - Last 100 Container Logs entries from STDOUT (cluster: $cluster)", + "type": "table" + } + ], + "title": "Expand this row to show STDOUT logs", + "type": "row" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "description": "Defines the service Component this report focuses on.", + "hide": 2, + "name": "component", + "query": "${VAR_COMPONENT}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_COMPONENT}", + "text": "${VAR_COMPONENT}", + "selected": false + }, + "options": [ + { + "value": "${VAR_COMPONENT}", + "text": "${VAR_COMPONENT}", + "selected": false + } + ] + }, + { + "description": "Defines the service Component this report focuses on.", + "hide": 2, + "name": "component_text", + "query": "${VAR_COMPONENT_TEXT}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_COMPONENT_TEXT}", + "text": "${VAR_COMPONENT_TEXT}", + "selected": false + }, + "options": [ + { + "value": "${VAR_COMPONENT_TEXT}", + "text": "${VAR_COMPONENT_TEXT}", + "selected": false + } + ] + }, + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_node_status_condition", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "kube_node_status_condition", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*cluster=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "hide": 2, + "includeAll": true, + "multi": true, + "name": "namespace", + "options": [], + "query": { + "query": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "description": "Pipeline RegEx for the self-test pipeline", + "hide": 2, + "name": "bf_pipeline4selftest", + "query": "${VAR_BF_PIPELINE4SELFTEST}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_BF_PIPELINE4SELFTEST}", + "text": "${VAR_BF_PIPELINE4SELFTEST}", + "selected": false + }, + "options": [ + { + "value": "${VAR_BF_PIPELINE4SELFTEST}", + "text": "${VAR_BF_PIPELINE4SELFTEST}", + "selected": false + } + ] + }, + { + "description": "Latency threshold for health signal", + "hide": 2, + "label": "", + "name": "aio_opc_latency_threshold_ms", + "query": "${VAR_AIO_OPC_LATENCY_THRESHOLD_MS}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_AIO_OPC_LATENCY_THRESHOLD_MS}", + "text": "${VAR_AIO_OPC_LATENCY_THRESHOLD_MS}", + "selected": false + }, + "options": [ + { + "value": "${VAR_AIO_OPC_LATENCY_THRESHOLD_MS}", + "text": "${VAR_AIO_OPC_LATENCY_THRESHOLD_MS}", + "selected": false + } + ] + }, + { + "hide": 2, + "name": "latency_percentile", + "query": "${VAR_LATENCY_PERCENTILE}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_LATENCY_PERCENTILE}", + "text": "${VAR_LATENCY_PERCENTILE}", + "selected": false + }, + "options": [ + { + "value": "${VAR_LATENCY_PERCENTILE}", + "text": "${VAR_LATENCY_PERCENTILE}", + "selected": false + } + ] + }, + { + "auto": true, + "auto_count": 300, + "auto_min": "5m", + "current": { + "selected": false, + "text": "auto", + "value": "$__auto_interval_latency_quantile_range" + }, + "hide": 2, + "name": "latency_quantile_range", + "options": [ + { + "selected": true, + "text": "auto", + "value": "$__auto_interval_latency_quantile_range" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "15m", + "value": "15m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "3h", + "value": "3h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "24h", + "value": "24h" + } + ], + "query": "5m,10m,15m,1h,3h,6h,24h", + "queryValue": "", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + }, + { + "description": "Success Rate goal for SLOs; below this value is considered missed SLO", + "hide": 2, + "name": "aio_opc_slo_sr_goal", + "query": "${VAR_AIO_OPC_SLO_SR_GOAL}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_AIO_OPC_SLO_SR_GOAL}", + "text": "${VAR_AIO_OPC_SLO_SR_GOAL}", + "selected": false + }, + "options": [ + { + "value": "${VAR_AIO_OPC_SLO_SR_GOAL}", + "text": "${VAR_AIO_OPC_SLO_SR_GOAL}", + "selected": false + } + ] + }, + { + "description": "Latency goal for SLOs (in milliseconds); above this value is considered missed SLO", + "hide": 2, + "name": "aio_opc_slo_publish_latency_ms_goal", + "query": "${VAR_AIO_OPC_SLO_PUBLISH_LATENCY_MS_GOAL}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_AIO_OPC_SLO_PUBLISH_LATENCY_MS_GOAL}", + "text": "${VAR_AIO_OPC_SLO_PUBLISH_LATENCY_MS_GOAL}", + "selected": false + }, + "options": [ + { + "value": "${VAR_AIO_OPC_SLO_PUBLISH_LATENCY_MS_GOAL}", + "text": "${VAR_AIO_OPC_SLO_PUBLISH_LATENCY_MS_GOAL}", + "selected": false + } + ] + }, + { + "description": "Latency goal for SLOs (in milliseconds); above this value is considered missed SLO", + "hide": 2, + "name": "aio_opc_slo_connect_latency_ms_goal", + "query": "${VAR_AIO_OPC_SLO_CONNECT_LATENCY_MS_GOAL}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_AIO_OPC_SLO_CONNECT_LATENCY_MS_GOAL}", + "text": "${VAR_AIO_OPC_SLO_CONNECT_LATENCY_MS_GOAL}", + "selected": false + }, + "options": [ + { + "value": "${VAR_AIO_OPC_SLO_CONNECT_LATENCY_MS_GOAL}", + "text": "${VAR_AIO_OPC_SLO_CONNECT_LATENCY_MS_GOAL}", + "selected": false + } + ] + }, + { + "current": {}, + "hide": 0, + "includeAll": false, + "multi": false, + "name": "query0", + "options": [], + "query": "", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + }, + { + "hide": 2, + "name": "opc_ua_broker_dashboard_path", + "query": "${VAR_OPC_UA_BROKER_DASHBOARD_PATH}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_OPC_UA_BROKER_DASHBOARD_PATH}", + "text": "${VAR_OPC_UA_BROKER_DASHBOARD_PATH}", + "selected": false + }, + "options": [ + { + "value": "${VAR_OPC_UA_BROKER_DASHBOARD_PATH}", + "text": "${VAR_OPC_UA_BROKER_DASHBOARD_PATH}", + "selected": false + } + ] + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "aio-health-service-opcua", + "uid": "ba43ff7a-e741-4965-b430-c9d4bf1757a6", + "version": 19, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-health-service-orch-1698853622327.json b/samples/dashboard/grafana-dashboards/aio-health-service-orch-1698853622327.json new file mode 100644 index 0000000..70d5e6a --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-health-service-orch-1698853622327.json @@ -0,0 +1,3333 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + }, + { + "name": "DS_AZURE_MONITOR", + "label": "Azure Monitor", + "description": "", + "type": "datasource", + "pluginId": "grafana-azure-monitor-datasource", + "pluginName": "Azure Monitor" + }, + { + "name": "VAR_COMPONENT", + "type": "constant", + "label": "component", + "value": "^(aio-orc-).*", + "description": "" + }, + { + "name": "VAR_COMPONENT_TEXT", + "type": "constant", + "label": "component_text", + "value": "Orchestrator", + "description": "" + }, + { + "name": "VAR_AIO_ORC_LATENCY_THRESHOLD_MS", + "type": "constant", + "label": "aio_orc_latency_threshold_ms", + "value": "60000", + "description": "" + }, + { + "name": "VAR_LATENCY_PERCENTILE", + "type": "constant", + "label": "latency_percentile", + "value": "0.99", + "description": "" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "grafana-azure-monitor-datasource", + "name": "Azure Monitor", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "piechart", + "name": "Pie chart", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "state-timeline", + "name": "State timeline", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 8, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n Azure Edge Services - ${component_text} Health\n
\n
\n   Scenario Health (SLO/RUM) related to ${component_text}\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 10, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Service Health (Synthetics/Self-test)\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 60, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for ${component_text} ${__field.labels._}", + "url": "${__field.labels.url}?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#7f7f7f", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + }, + { + "color": "#7f7f7f", + "value": 404 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "^Self-test.*[^)]$" + }, + "properties": [ + { + "id": "links" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".* Overall Health$" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 1 + }, + { + "id": "links" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 16, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.72, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(min(\r\n label_replace(#label_replace(\r\n (min(\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_orc_api_operation_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) < $aio_orc_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_orc_api_operation_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) >= $aio_orc_latency_threshold_ms) or\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_orc_provider_operation_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) < $aio_orc_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_orc_provider_operation_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) >= $aio_orc_latency_threshold_ms) or\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_orc_controller_validation_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) < $aio_orc_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_orc_controller_validation_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) >= $aio_orc_latency_threshold_ms) or\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_orc_controller_reconcile_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) < $aio_orc_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_orc_controller_reconcile_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) >= $aio_orc_latency_threshold_ms) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"Orchestrator latency P95\",\"\",\"\") or\r\n label_replace(#label_replace(\r\n (min(\r\n 0 * sgn(0 < round(sum(increase(aio_orc_api_operation_errors{cluster=~\"$cluster\"}[$__rate_interval])))) or\r\n 1 * sgn(aio_orc_api_operation_latency_count{cluster=~\"$cluster\"}) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"API Operation errors\",\"\",\"\") or\r\n label_replace(#label_replace(\r\n (min(\r\n 0 * sgn(0 < round(sum(increase(aio_orc_provider_operation_errors{cluster=~\"$cluster\"}[$__rate_interval])))) or\r\n 1 * sgn(aio_orc_provider_operation_latency_count{cluster=~\"$cluster\"}) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"Provider Operation errors\",\"\",\"\") or\r\n vector(0)>0\r\n),\"_\",\"$component_text Overall Health\",\"\",\"\")", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# label_replace(min(\r\n label_replace(#label_replace(\r\n (min(\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_orc_api_operation_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) < $aio_orc_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_orc_api_operation_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) >= $aio_orc_latency_threshold_ms) or\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_orc_provider_operation_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) < $aio_orc_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_orc_provider_operation_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) >= $aio_orc_latency_threshold_ms) or\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_orc_controller_validation_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) < $aio_orc_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n aio_orc_controller_reconcile_latency_bucket{cluster=~\"$cluster\"}[5m]\r\n ))) >= $aio_orc_latency_threshold_ms) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"Orchestrator latency P95\",\"\",\"\") or\r\n label_replace(#label_replace(\r\n (min(\r\n 0 * sgn(0 < round(sum(increase(aio_orc_api_operation_errors{cluster=~\"$cluster\"}[$__rate_interval])))) or\r\n 1 * sgn(aio_orc_api_operation_latency_count{cluster=~\"$cluster\"}) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"API Operation errors\",\"\",\"\") or\r\n label_replace(#label_replace(\r\n (min(\r\n 0 * sgn(0 < round(sum(increase(aio_orc_provider_operation_errors{cluster=~\"$cluster\"}[$__rate_interval])))) or\r\n 1 * sgn(aio_orc_provider_operation_latency_count{cluster=~\"$cluster\"}) or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"Provider Operation errors\",\"\",\"\") or\r\n vector(0)>0\r\n# ),\"_\",\"$component_text Overall Health\",\"\",\"\")", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "B" + } + ], + "title": "Service Health", + "transformations": [], + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 12, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Golden Metrics\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [ + { + "options": { + "match": "null+nan", + "result": { + "color": "transparent", + "index": 0 + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".*s$" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisLabel", + "value": "total count" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*[/]sec[)]$" + }, + "properties": [ + { + "id": "custom.axisLabel", + "value": "throughput (msgs/sec)" + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 15 + }, + "id": 50, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(sum(increase(aio_orc_controller_validation_latency_count{cluster=\"$cluster\"}[$__rate_interval])), \"_\", \"Controller Validation Operation\", \"\", \"\") or\r\nlabel_replace(sum(increase(aio_orc_controller_reconcile_latency_count{cluster=\"$cluster\"}[$__rate_interval])), \"_\", \"Controller Reconcile Operation\", \"\", \"\") or\r\nlabel_replace(sum(increase(aio_orc_api_operation_latency_count{cluster=\"$cluster\"}[$__rate_interval])), \"_\", \"API Operation\", \"\", \"\") or\r\nlabel_replace(sum(increase(aio_orc_provider_operation_latency_count{cluster=\"$cluster\"}[$__rate_interval])), \"_\", \"Provider Operation\", \"\", \"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Usage/Volume", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "red", + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 29, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Success Rate" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 3 + }, + { + "id": "custom.axisSoftMin", + "value": 0 + }, + { + "id": "custom.axisSoftMax", + "value": 101 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*(Errors)$" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "unit", + "value": "none" + }, + { + "id": "custom.axisLabel", + "value": "Error Count" + }, + { + "id": "custom.drawStyle", + "value": "bars" + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "custom.axisSoftMin", + "value": 0 + }, + { + "id": "custom.axisSoftMax", + "value": 20 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 15 + }, + "id": 51, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "label_replace(\r\n increase(aio_orc_api_operation_errors{cluster=\"$cluster\"}[$__rate_interval]),\r\n \"_\",\"API \",\"\",\"\") or\r\nlabel_replace(\r\n increase(aio_orc_provider_operation_errors{cluster=\"$cluster\"}[$__rate_interval]),\r\n \"_\",\"Provider \",\"\",\"\")", + "hide": false, + "legendFormat": "{{_}} {{providertype}}.{{operation}} (error: {{errorcode}} )", + "range": true, + "refId": "A" + } + ], + "title": "Errors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "Self-test.*" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 0, + 10 + ], + "fill": "dot" + } + } + ] + }, + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "Worst Controller Reconcile Latency" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 15 + }, + "id": 52, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#ping_latency_last_value_ms{cluster=\"$cluster\"} or\r\nmax by (_)(\r\n label_replace(label_replace(label_replace(#quantile_over_time($latency_percentile,\r\n histogram_quantile($latency_percentile, sum(rate(aio_orc_api_operation_latency_bucket{cluster=~\"$cluster\"}[$latency_quantile_range])) by (le,cloud_resource_id))\r\n #[$latency_quantile_range:])\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"API Operation Latency\",\"pout\",\"(.*)\") or\r\n label_replace(label_replace(label_replace(#quantile_over_time($latency_percentile,\r\n histogram_quantile($latency_percentile, sum(rate(aio_orc_controller_reconcile_latency_bucket{cluster=~\"$cluster\"}[$latency_quantile_range])) by (le,cloud_resource_id))\r\n #[$latency_quantile_range:])\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"Worst Controller Reconcile Latency\",\"pout\",\"(.*)\") or\r\n label_replace(label_replace(label_replace(#quantile_over_time($latency_percentile,\r\n histogram_quantile($latency_percentile, sum(rate(aio_orc_controller_validation_latency_bucket{cluster=~\"$cluster\"}[$latency_quantile_range])) by (le,cloud_resource_id))\r\n #[$latency_quantile_range:])\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"Worst Controller Validation Latency\",\"pout\",\"(.*)\") or\r\n label_replace(label_replace(label_replace(#quantile_over_time($latency_percentile,\r\n histogram_quantile($latency_percentile, rate(aio_orc_api_operation_latency_bucket{cluster=~\"$cluster\"}[$latency_quantile_range]))\r\n #[$latency_quantile_range:])\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"Worst API Operation Latency $1\",\"pout\",\"(.*)\") or\r\n label_replace(label_replace(label_replace(#quantile_over_time($latency_percentile,\r\n histogram_quantile($latency_percentile, sum(rate(aio_orc_provider_operation_latency_bucket{cluster=~\"$cluster\"}[$latency_quantile_range])) by (le,cloud_resource_id))\r\n #[$latency_quantile_range:])\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"Worst Provider Operation Latency\",\"pout\",\"(.*)\") or\r\n label_replace(label_replace(label_replace(#quantile_over_time($latency_percentile,\r\n histogram_quantile($latency_percentile, rate(aio_orc_provider_operation_latency_bucket{cluster=~\"$cluster\"}[$latency_quantile_range]))\r\n #[$latency_quantile_range:])\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"Provider Operation Latency $1\",\"pout\",\"(.*)\") or\r\n label_replace(label_replace(label_replace(#quantile_over_time($latency_percentile,\r\n histogram_quantile($latency_percentile, rate(aio_orc_controller_reconcile_latency_bucket{cluster=~\"$cluster\"}[$latency_quantile_range]))\r\n #[$latency_quantile_range:])\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"Controller Reconcile Latency $1\",\"pout\",\"(.*)\") or\r\n label_replace(label_replace(label_replace(#quantile_over_time($latency_percentile,\r\n histogram_quantile($latency_percentile, rate(aio_orc_controller_validation_latency_bucket{cluster=~\"$cluster\"}[$latency_quantile_range]))\r\n #[$latency_quantile_range:])\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"Controller Validation Latency $1\",\"pout\",\"(.*)\") or\r\n vector(0)>0) or\r\n#label_replace(vector(1),\"_\",\"TODO: Latency\",\"\",\"\") or\r\nvector(0)>0", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(histogram_quantile(0.99, rate(aio_orc_api_operation_latency_bucket{cluster=~\"$cluster\"}[$__rate_interval])),\"_\",\"\",\"\",\"\") or\r\nlabel_replace(histogram_quantile(0.99, rate(aio_orc_provider_operation_latency_bucket{cluster=~\"$cluster\"}[$__rate_interval])),\"_\",\"\",\"\",\"\") or\r\nlabel_replace(histogram_quantile(0.99, rate(aio_orc_controller_reconcile_latency_bucket{cluster=~\"$cluster\"}[$__rate_interval])),\"_\",\"\",\"\",\"\") or\r\nlabel_replace(histogram_quantile(0.99, rate(aio_orc_controller_validation_latency_bucket{cluster=~\"$cluster\"}[$__rate_interval])),\"_\",\"\",\"\",\"\") or\r\nvector(0)>0", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 11, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Infrastructure Workload Health\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "Click for more details", + "url": "/d/eef9bf1c-b27a-4e86-a7f0-2a39cdfbeeca/health-infrastructure?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 25 + }, + "id": 31, + "links": [ + { + "targetBlank": true, + "title": "See infra workload health for all components", + "url": "/d/E5cCeHj4z/health-infra-workload?${cluster:queryparam}&${__url_time_range}" + } + ], + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.9, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Workload Readiness health\r\n############################\r\nlabel_replace(min(\r\navg(label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n label_replace(label_join(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n / label_replace(label_join(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n) by (workload) >=0 \r\n) or vector(0),\"_\",\"Workload Readiness\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Restart Health:\r\n############################\r\nlabel_replace(\r\n sgn(sum_over_time(sum(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[10m:1m]\r\n )*60)[1h:]) > 5) * 0.0 # RED: Cumulative restarts over X(5) time greater than Y(1h)\r\n or (max(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[5m:1m]\r\n )*60*5) > 0) * 0.5 # YELLOW: restarts detected but below Red threshold\r\n or sgn(max(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}\r\n + 1 >= 0))\r\n #or vector(1) # Healthy\r\n ,\"_\",\"Container Restart Health\",\"\",\"\")\r\n## uncomment below to t-shoot this health metric\r\n# or label_replace(sum_over_time(sum(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[10m:1m])*60)[1h:]),\"_\",\"Total-restarts-over-time\",\"\",\"\")\r\n# or label_replace((max(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[5m:1m])*60*5) without (__name__,uid,instance,job) > 0),\"_\",\"restart\",\"\",\"\") # Base query for counting restarts\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container CPU top-level health\r\n################################\r\nlabel_replace(\r\nmin(sgn( # Check for throttling > N indicating container is exceeding its CPU limits\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m]) \r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m])\r\n >= 0.60) # If throttle create is greater than this percentage, we'll multiply sgn by 0.5 to show as error (or warning depending on threshold coloring)\r\n ) # by (namespace,container) # These are commented out for top-level\r\n * 0.0\r\nor\r\nmin(sgn( # Check for throttling > N indicating container is exceeding its CPU limits\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m]) \r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m])\r\n >= 0.40) # If throttle create is greater than this percentage, we'll multiply sgn by 0.5 to show as error (or warning depending on threshold coloring)\r\n ) # by (namespace,container) # These are commented out for top-level\r\n * 0.5\r\nor\r\nmin( # Check to see if container is missing CPU Limits configuration\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"cpu\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n ) #by (namespace,container) # These are commented out for top-level\r\n,\"_\",\"Container CPU Health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Memory Health:\r\n###########################\r\nlabel_replace(\r\nmin( # Look for high memory utilization\r\n sgn((\r\n max(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container)\r\n / min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"memory\",pod=~\"${component:raw}\"}) by (namespace, container)\r\n ) >= .95) - 0.5 # show health state of 0.5 if container memory utilization >= 95%\r\n) #by (container) \r\nor\r\nmin( # Look for missing limits which we will show as 0 if missing\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"memory\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n) #by (container) \r\n,\"_\",\"Container Memory health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Health Summary", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "max(rate(container_cpu_usage_seconds_total{namespace=~\"alice-springs|symphony-k8s-system\",container=\"\",cpu=\"total\"}[5m])*300 > 0) ": "POD CPU (max)", + "min( # Workload ready percents (for deployment, daemonset, replicaset, and statefulset)\r\n label_replace(label_join(\r\n {job=\"kube-state-metrics\",namespace=~\"alice-springs|symphony-k8s-system\",\r\n __name__=~\"kube_(deployment|daemonset|replicaset|statefulset)_status_(replicas_ready|ready_replicas|number_ready)\"}\r\n ,\"workload\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n / label_replace(label_join(\r\n {job=\"kube-state-metrics\",namespace=~\"alice-springs|symphony-k8s-system\",\r\n __name__=~\"kube_(deployment|daemonset|replicaset|statefulset)_status_(replicas|desired_number_scheduled)\"}\r\n ,\"workload\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n) #by (workloadType) #namespace) #, workloadType) #, workload)": "Workload ready health" + } + } + } + ], + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 20 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 6, + "y": 25 + }, + "id": 33, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(sum ( # by(workloadType) (\r\n#min(\r\n# label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n label_replace(label_join(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n),\"_\",\"Ready\",\"\",\"\")\r\n# / label_replace(label_join(\r\n# kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\"$namespace\",daemonset=~\"${component:raw}\"} or\r\n# kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\"$namespace\",deployment=~\"${component:raw}\"} or\r\n# kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\"$namespace\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n# ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n#) by (workload) >=0 ", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#min(\r\n# label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n# label_replace(label_join(\r\n# kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",deployment=~\"${component:raw}\"} or\r\n# kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",daemonset=~\"${component:raw}\"} or\r\n# kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n# / label_replace(label_join(\r\n label_replace(sum(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n ),\"_\",\"Requested\",\"\",\"\")\r\n# ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n#) by (workload) >=0 ", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Workloads", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 8, + "y": 25 + }, + "id": 35, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor label_replace(vector(0),\"status\",\"Ready\",\"\",\"\")\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "DaemonSets", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 10, + "y": 25 + }, + "id": 37, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor label_replace(vector(0),\"status\",\"Ready\",\"\",\"\") # this is to zero if no workloads of this type exist\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "Deployments", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 12, + "y": 25 + }, + "id": 39, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor \r\nlabel_replace(vector(0),\"status\",\"Ready\",\"\",\"\")\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "StatefulSets", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 1 + }, + { + "color": "dark-orange", + "value": 5 + }, + { + "color": "red", + "value": 10 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 14, + "y": 25 + }, + "id": 41, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Container Restarts\r\nlabel_replace(ceil(sum_over_time(sum(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[10m:1m])*60)[1h:])),\"_\",\"restarts\",\"\",\"\")\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 40 + }, + { + "color": "red", + "value": 60 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percent containers with CPU Limits (%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "super-light-purple", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Usage (milli-cores)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisColorMode", + "value": "series" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Max Throttled (%)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "thresholds", + "seriesBy": "max" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 25 + }, + "id": 59, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\n(label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))*1000,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\") )\r\n# Percent of containers with limits defined\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"Percent containers with CPU Limits (%)\",\"\",\"\")\r\n# CPU Throttling:\r\nor label_replace(100*(max(\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n )),\"_\",\"CPU Max Throttled (%)\",\"\",\"\")\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(quantile_over_time(0.95,sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\nvector(0)>0\r\n# Sum of all limits defined, in Cores\r\nor label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# WIP:\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"WIP-PERCENT_WITH_LIMITS\",\"\",\"\")\r\nor label_replace(count(\r\n kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"})\r\n ,\"_\",\"WIP-NUMERATOR\",\"\",\"\")\r\nor label_replace(count(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) #without(cluster,container,cpu,id,image,instance,job,name,namespace,pod)\r\n ,\"_\",\"WIP-DENOMINATOR\",\"\",\"\")\r\n# ", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "CPU", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 80 + }, + { + "color": "orange", + "value": 85 + }, + { + "color": "red", + "value": 90 + }, + { + "color": "dark-red", + "value": 95 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percent containers with Memory Limits (%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mem Working Bytes (MB)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisColorMode", + "value": "series" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mem Max Usage vs Limit (%)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "thresholds", + "seriesBy": "max" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 25 + }, + "id": 61, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory Usage (MB version)\r\n(label_replace(sum(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"Mem Working Bytes (MB)\",\"\",\"\") )\r\n# Percent containers with limits\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"memory\"}) /\r\n count(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}) *100\r\n ,\"_\",\"Percent containers with Memory Limits (%)\",\"\",\"\")\r\n# Max Mem % Usage:\r\nor label_replace(100*(max(\r\n max_over_time((max by(container)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}))[10m:])\r\n / max by(container)(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"memory\"})\r\n )),\"_\",\"Mem Max Usage vs Limit (%)\",\"\",\"\")\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(quantile_over_time(0.95,sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\nvector(0)>0\r\n# Sum of all limits defined, in Cores\r\nor label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# WIP:\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"WIP-PERCENT_WITH_LIMITS\",\"\",\"\")\r\nor label_replace(count(\r\n kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"})\r\n ,\"_\",\"WIP-NUMERATOR\",\"\",\"\")\r\nor label_replace(count(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) #without(cluster,container,cpu,id,image,instance,job,name,namespace,pod)\r\n ,\"_\",\"WIP-DENOMINATOR\",\"\",\"\")\r\n# ", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "milli-cores", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels._}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels._}.*" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Overall" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "number" + }, + "properties": [ + { + "id": "links" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 29 + }, + "id": 47, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(_)(\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum by(pod)(rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") or\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum (rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\".Overall\",\"\",\"\") or\r\nvector(0)>0)", + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + } + ], + "title": "CPU Usage by Workload", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "working bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels._}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels._}.*" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byType", + "options": "number" + }, + "properties": [ + { + "id": "links" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 29 + }, + "id": 48, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(_)(\r\nlabel_replace(\r\n sum by(pod)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") \r\n)\r\n##(label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))*1000,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\") )\r\n## and label_replace(max_over_time(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))[3d:]) < 0.2,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\")) # Show milli-cores if rate below 0.2 cores\r\n# CPU Time (cores version, if >= 0.2 cores)\r\n##or (label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval])),\"_\",\"CPU Usage (cores)\",\"\",\"\") \r\n## and label_replace(max_over_time(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))[3d:]) >= 0.2,\"_\",\"CPU Usage (cores)\",\"\",\"\")) # Show in cores if rate at or above 0.2 cores\r\n# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(max_over_time(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\n# Sum of all limits defined, in Cores\r\n##or label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# CPU Throttling:\r\n##or label_replace(100*(max(\r\n## rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n## / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n## )),\"_\",\"CPU Max Throttled (%)\",\"\",\"\")\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Memory Usage by Workload", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Click on data series to drill down into pod details", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "milli-cores", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels.pod}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels.pod}" + } + ], + "mappings": [ + { + "options": { + "match": "null+nan", + "result": { + "color": "transparent", + "index": 0 + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Overall" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 37 + }, + "id": 56, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(pod)(\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum by(pod)(rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\"$1\",\"pod\",\"(.*)\") or #,\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") or\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum (rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"pod\",\".Overall\",\"\",\"\") or\r\nvector(0)>0)", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(_)(\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum by(pod)(rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") or\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum (rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\".Overall\",\"\",\"\") or\r\nvector(0)>0)", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "CPU Usage by Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Click on data series to drill down into pod details", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "working bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels.pod}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels.pod}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 37 + }, + "id": 57, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory working bytes\r\nmax by(pod)(\r\nlabel_replace(\r\n sum by(pod)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") \r\n)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory working bytes\r\nmax by(_)(\r\nlabel_replace(\r\n sum by(pod)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") \r\n)", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Memory Usage by Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 45 + }, + "id": 13, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Errors & Logs\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "yellow", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PodName" + }, + "properties": [ + { + "id": "custom.width", + "value": 300 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Reason" + }, + "properties": [ + { + "id": "custom.width", + "value": 112 + }, + { + "id": "custom.align", + "value": "center" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "Failed": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ] + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Count" + }, + "properties": [ + { + "id": "custom.width", + "value": 114 + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "color", + "value": { + "mode": "continuous-BlPu" + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.width", + "value": 200 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Message" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 55, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "LastSeen" + } + ] + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "azureLogAnalytics": { + "query": "KubeEvents\r\n//| where TimeGenerated > ago(1d)\r\n| where ClusterName == '$cluster'\r\n| where Name matches regex '${component:raw}'\r\n//| order by TimeGenerated desc\r\n| order by LastSeen desc, FirstSeen desc, TimeGenerated desc\r\n| project-rename PodName = Name\r\n| project FirstSeen, LastSeen, Count, PodName, Reason, Message\r\n| take 10", + "resources": [ + "/subscriptions/af342bf1-1ace-41df-902c-47921400551b" + ], + "resultFormat": "table" + }, + "azureMonitor": { + "allowedTimeGrainsMs": [], + "timeGrain": "auto" + }, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "queryType": "Azure Log Analytics", + "refId": "A" + } + ], + "title": "Last 10 Kube Events entries (from $cluster)", + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 55 + }, + "id": 14, + "links": [ + { + "targetBlank": true, + "title": "Open ${component_text} - Overview page", + "url": "/d/e57b7777-71be-43a8-87bd-d917391b154f/bluefin-overview?${__all_variables}&${__url_time_range}" + } + ], + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   ${component_text}-specific\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed+area" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent" + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 57 + }, + "id": 65, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "histogram_quantile(0.95, aio_orc_controller_validation_latency_bucket{cluster=\"$cluster\"})", + "hide": false, + "instant": false, + "legendFormat": " {{resourcetype}} {{validationtype}} ({{validationresult}}) ", + "range": true, + "refId": "A" + } + ], + "title": "Controller Validation Latency P95", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed+area" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent" + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 65 + }, + "id": 66, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "avg by(resourcetype, reconciliationtype, reconciliationresult) (histogram_quantile(0.95, aio_orc_controller_reconcile_latency_bucket{cluster=\"$cluster\"}))", + "hide": false, + "instant": false, + "legendFormat": "{{resourcetype}} {{reconciliationtype}} ({{reconciliationresult}})", + "range": true, + "refId": "A" + } + ], + "title": "Controller Reconcile Latency P95", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic", + "seriesBy": "max" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent" + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "reconcile" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "getsummary" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-purple", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 74 + }, + "id": 29, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "desc" + } + }, + "pluginVersion": "9.5.8", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, aio_orc_api_operation_latency_bucket{cluster=\"$cluster\"})", + "format": "time_series", + "hide": false, + "interval": "", + "legendFormat": "{{operation}}", + "range": true, + "refId": "A" + } + ], + "title": "API Operation Latency P95", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed+area" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent" + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 82 + }, + "id": 62, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "histogram_quantile(0.95, aio_orc_provider_operation_latency_bucket{cluster=\"$cluster\"})", + "hide": false, + "instant": false, + "legendFormat": "{{providertype}} {{functionname}}", + "range": true, + "refId": "A" + } + ], + "title": "Provider Operation Latency P95", + "transformations": [], + "type": "timeseries" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "description": "Defines the service Component this report focuses on.", + "hide": 2, + "name": "component", + "query": "${VAR_COMPONENT}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_COMPONENT}", + "text": "${VAR_COMPONENT}", + "selected": false + }, + "options": [ + { + "value": "${VAR_COMPONENT}", + "text": "${VAR_COMPONENT}", + "selected": false + } + ] + }, + { + "description": "Defines the service Component this report focuses on.", + "hide": 2, + "name": "component_text", + "query": "${VAR_COMPONENT_TEXT}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_COMPONENT_TEXT}", + "text": "${VAR_COMPONENT_TEXT}", + "selected": false + }, + "options": [ + { + "value": "${VAR_COMPONENT_TEXT}", + "text": "${VAR_COMPONENT_TEXT}", + "selected": false + } + ] + }, + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_node_status_condition", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "kube_node_status_condition", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*cluster=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "hide": 2, + "includeAll": true, + "multi": true, + "name": "namespace", + "options": [], + "query": { + "query": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "description": "Latency threshold for health signal", + "hide": 2, + "label": "", + "name": "aio_orc_latency_threshold_ms", + "query": "${VAR_AIO_ORC_LATENCY_THRESHOLD_MS}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_AIO_ORC_LATENCY_THRESHOLD_MS}", + "text": "${VAR_AIO_ORC_LATENCY_THRESHOLD_MS}", + "selected": false + }, + "options": [ + { + "value": "${VAR_AIO_ORC_LATENCY_THRESHOLD_MS}", + "text": "${VAR_AIO_ORC_LATENCY_THRESHOLD_MS}", + "selected": false + } + ] + }, + { + "hide": 2, + "name": "latency_percentile", + "query": "${VAR_LATENCY_PERCENTILE}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_LATENCY_PERCENTILE}", + "text": "${VAR_LATENCY_PERCENTILE}", + "selected": false + }, + "options": [ + { + "value": "${VAR_LATENCY_PERCENTILE}", + "text": "${VAR_LATENCY_PERCENTILE}", + "selected": false + } + ] + }, + { + "auto": true, + "auto_count": 300, + "auto_min": "5m", + "current": { + "selected": false, + "text": "auto", + "value": "$__auto_interval_latency_quantile_range" + }, + "hide": 2, + "name": "latency_quantile_range", + "options": [ + { + "selected": true, + "text": "auto", + "value": "$__auto_interval_latency_quantile_range" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "15m", + "value": "15m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "3h", + "value": "3h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "24h", + "value": "24h" + } + ], + "query": "5m,10m,15m,1h,3h,6h,24h", + "queryValue": "", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "aio-health-service-orch", + "uid": "f42af83d-1bfe-4bdd-966b-ff1886fee8c6", + "version": 83, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-service-dp-messagestore-1698853668951.json b/samples/dashboard/grafana-dashboards/aio-service-dp-messagestore-1698853668951.json new file mode 100644 index 0000000..a6ad5ec --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-service-dp-messagestore-1698853668951.json @@ -0,0 +1,1469 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Data Processor message store dashboard", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "decimals": 3, + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 0.75 + }, + { + "color": "red", + "value": 0.9 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 0, + "y": 0 + }, + "id": 28, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "expr": "sum(nats_varz_jetstream_stats_storage{cluster=\"$cluster\",server_id=~\"$server\"})/sum(nats_varz_jetstream_config_max_storage{cluster=\"$cluster\",server_id=~\"$server\"})", + "interval": "", + "legendFormat": "", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "expr": "", + "interval": "", + "legendFormat": "", + "refId": "B" + } + ], + "title": "Storage Used", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "min": 0, + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 4, + "y": 0 + }, + "id": 15, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "expr": "sum(nats_varz_jetstream_stats_storage{cluster=\"$cluster\",server_id=~\"$server\"})", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Total Storage Used", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "decimals": 3, + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 0.75 + }, + { + "color": "red", + "value": 0.9 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 9, + "y": 0 + }, + "id": 31, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "expr": "sum(nats_varz_jetstream_stats_memory{cluster=\"$cluster\",server_id=~\"$server\"})/sum(nats_varz_jetstream_config_max_memory{cluster=\"$cluster\",server_id=~\"$server\"})", + "interval": "", + "legendFormat": "", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "expr": "", + "interval": "", + "legendFormat": "", + "refId": "B" + } + ], + "title": "Memory Used", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "min": 0, + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 13, + "y": 0 + }, + "id": 32, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "expr": "sum(nats_varz_jetstream_stats_memory{cluster=\"$cluster\",server_id=~\"$server\"})", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Memory Used", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 0 + }, + "id": 14, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "expr": "sum(nats_varz_connections{cluster=\"$cluster\",server_id=~\"$server\"})", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Connections", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "min": 0, + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 4, + "y": 3 + }, + "id": 30, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "expr": "sum(nats_varz_jetstream_config_max_storage{cluster=\"$cluster\",server_id=~\"$server\"})", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Max Storage", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "min": 0, + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 13, + "y": 3 + }, + "id": 33, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "expr": "sum(nats_varz_jetstream_config_max_memory{cluster=\"$cluster\",server_id=~\"$server\"})", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Total Memory", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 29, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "expr": "sum(nats_server_total_consumers{cluster=\"$cluster\",server_id=~\"$server\"})", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Total Consumers", + "type": "stat" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "jajens-azmonworkspace-test" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 19, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "jajens-azmonworkspace-test" + }, + "refId": "A" + } + ], + "title": "Stream metrics", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 7 + }, + "id": 17, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "expr": "sum(nats_stream_total_bytes{cluster=\"$cluster\"}) by (stream_name)", + "interval": "", + "legendFormat": "{{stream_name}}", + "refId": "A" + } + ], + "title": "Stream data size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "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": 6, + "w": 8, + "x": 8, + "y": 7 + }, + "id": 24, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "expr": "sum(nats_stream_total_messages{cluster=\"$cluster\"}) by (stream_name)", + "interval": "", + "legendFormat": "{{stream_name}}", + "refId": "A" + } + ], + "title": "Stream message count", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "mps" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 7 + }, + "id": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "expr": "sum(rate(nats_stream_total_messages{cluster=\"$cluster\",server_id=~\"$server\",stream_name=~\"$stream\"}[$__rate_interval])) by (stream_name)", + "hide": false, + "interval": "", + "legendFormat": "{{stream_name}}", + "refId": "A" + } + ], + "title": "Message Rate (per second)", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "jajens-azmonworkspace-test" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 23, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "jajens-azmonworkspace-test" + }, + "refId": "A" + } + ], + "title": "Consumer Metrics", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Messages added & processed per minute per consumer", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "mps" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 25, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "expr": "sum(rate(nats_consumer_num_pending{cluster=\"$cluster\",server_id=~\"$server\",stream_name=~\"$stream\",consumer_name=~\"$consumer\"}[$__rate_interval])+rate(nats_consumer_delivered_consumer_seq{cluster=\"$cluster\",server_id=~\"$server\",stream_name=~\"$stream\",consumer_name=~\"$consumer\"}[$__rate_interval])) by (consumer_name)", + "hide": false, + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{consumer_name}} +", + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "expr": "- sum(rate(nats_consumer_delivered_consumer_seq{cluster=\"$cluster\",server_id=~\"$server\",stream_name=~\"$stream\",consumer_name=~\"$consumer\",consumer_name=~\"$consumer\"}[$__rate_interval])) by (consumer_name)", + "hide": false, + "interval": "", + "legendFormat": "{{consumer_name}} -", + "refId": "A" + } + ], + "title": "Messages per second (++/--)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "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": 6, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 21, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "expr": "sum(nats_consumer_delivered_consumer_seq{cluster=\"$cluster\",server_id=~\"$server\",stream_name=~\"$stream\",consumer_name=~\"$consumer\"}) by (consumer_name)", + "hide": false, + "interval": "", + "legendFormat": "{{consumer_name}}", + "refId": "A" + } + ], + "title": "Total delivered messages", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 26, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "expr": "sum(nats_consumer_num_pending{cluster=\"$cluster\",server_id=~\"$server\",stream_name=~\"$stream\",consumer_name=~\"$consumer\"}) by (consumer_name)", + "hide": false, + "interval": "", + "legendFormat": "{{consumer_name}}", + "refId": "A" + } + ], + "title": "Pending messages", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 27, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "expr": "sum(nats_consumer_num_ack_pending{cluster=\"$cluster\",server_id=~\"$server\",stream_name=~\"$stream\",consumer_name=~\"$consumer\"}) by (consumer_name)", + "hide": false, + "interval": "", + "legendFormat": "{{consumer_name}}", + "refId": "A" + } + ], + "title": "Message Acks Pending", + "type": "timeseries" + } + ], + "refresh": "10s", + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "label_values(kube_node_status_condition,cluster)", + "hide": 0, + "includeAll": false, + "label": "Cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "label_values(kube_node_status_condition,cluster)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "label_values(nats_server_total_streams, server_id)", + "hide": 0, + "includeAll": true, + "label": "Server", + "multi": true, + "name": "server", + "options": [], + "query": { + "query": "label_values(nats_server_total_streams, server_id)", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "label_values(nats_stream_last_seq, stream_name)", + "hide": 0, + "includeAll": true, + "label": "Stream", + "multi": true, + "name": "stream", + "options": [], + "query": { + "query": "label_values(nats_stream_last_seq, stream_name)", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "label_values(nats_consumer_num_pending, consumer_name)", + "hide": 0, + "includeAll": true, + "label": "Consumer", + "multi": true, + "name": "consumer", + "options": [], + "query": { + "query": "label_values(nats_consumer_num_pending, consumer_name)", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "aio-service-dp-messagestore", + "uid": "e17d0b7f-9771-4cb8-adf9-56cbaef3fff6", + "version": 3, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-service-dp-overview-1698853677638.json b/samples/dashboard/grafana-dashboards/aio-service-dp-overview-1698853677638.json new file mode 100644 index 0000000..78c8f5e --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-service-dp-overview-1698853677638.json @@ -0,0 +1,2421 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + }, + { + "name": "DS_EXPRESSION", + "label": "Expression", + "description": "", + "type": "datasource", + "pluginId": "__expr__" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "datasource", + "id": "__expr__", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "state-timeline", + "name": "State timeline", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 9, + "panels": [], + "title": "Pipelines", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 0, + "y": 1 + }, + "id": 12, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_reader_incoming_messages{cluster=\"$cluster\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Input Messages", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 4, + "y": 1 + }, + "id": 13, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_stage_incoming_messages{cluster=\"$cluster\",stage_type=~\"output/.*\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Output Messages", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 1e-13 + } + ] + }, + "unit": "err/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 8, + "y": 1 + }, + "id": 15, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_stage_errors{cluster=\"$cluster\"}[$__rate_interval]))", + "legendFormat": "{{label_name}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_reader_errors{cluster=\"$cluster\"}[$__rate_interval]))", + "hide": false, + "legendFormat": "{{label_name}}", + "range": true, + "refId": "B" + } + ], + "title": "Processing Errors", + "transformations": [ + { + "id": "merge", + "options": {} + }, + { + "id": "calculateField", + "options": { + "mode": "reduceRow", + "reduce": { + "include": [ + "Value" + ], + "reducer": "sum" + }, + "replaceFields": true + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 100 + }, + { + "color": "red", + "value": 1000 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 12, + "y": 1 + }, + "id": 16, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(aio_dp_pipeline_latency_bucket{cluster=\"$cluster\"}[$__rate_interval])) by (le))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "E2E Latency (95th Percentile)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 16, + "y": 1 + }, + "id": 17, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "count(count by (cloud_resource_id, runner_partition) (rate(aio_dp_runner_info{cluster=\"$cluster\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Runner Count", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 20, + "y": 1 + }, + "id": 18, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "count(count by (cloud_resource_id, stage_id) (rate(aio_dp_stage_info{cluster=\"$cluster\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Stage Count", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "transparent", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "mode": "gradient", + "type": "color-background" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Input Messages" + }, + "properties": [ + { + "id": "color", + "value": { + "mode": "continuous-blues" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Output Messages" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "continuous-blues" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Errors" + }, + "properties": [ + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "red", + "value": 1 + } + ] + } + }, + { + "id": "color" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #A" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #B" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #C" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "cloud_resource_id" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "", + "url": "/d/4f637c27-a19f-489e-a4af-719f1baa0a19/aio-service-dp-pipeline?orgId=1&${cluster:queryparam}&{&var-pipeline=${__data.fields[\"cloud_resource_id\"]}&${__url_time_range}" + } + ] + }, + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 6 + }, + "id": 10, + "options": { + "cellHeight": "md", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "frameIndex": 0, + "showHeader": true + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(increase(aio_dp_stage_outgoing_messages{cluster=\"$cluster\",stage_type=~\"messagestore/.*\"}[$__range])) by (cloud_resource_id)", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(increase(aio_dp_stage_incoming_messages{cluster=\"$cluster\",stage_type=~\"output/.*\"}[$__range])) by (cloud_resource_id)", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(increase(aio_dp_stage_errors{cluster=\"$cluster\"}[$__range])) by (cloud_resource_id)", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "C" + } + ], + "title": "Pipeline Throughputs", + "transformations": [ + { + "filter": { + "id": "byRefId", + "options": "A" + }, + "id": "organize", + "options": { + "excludeByName": { + "reader_id": false + }, + "indexByName": {}, + "renameByName": { + "reader_id": "cloud_resource_id" + } + } + }, + { + "id": "merge", + "options": {} + }, + { + "id": "calculateField", + "options": { + "alias": "Input Messages", + "mode": "reduceRow", + "reduce": { + "include": [ + "Value #A" + ], + "reducer": "sum" + } + } + }, + { + "id": "calculateField", + "options": { + "alias": "Output Messages", + "mode": "reduceRow", + "reduce": { + "include": [ + "Value #B" + ], + "reducer": "sum" + } + } + }, + { + "id": "calculateField", + "options": { + "alias": "Errors", + "mode": "reduceRow", + "reduce": { + "include": [ + "Value #C" + ], + "reducer": "sum" + } + } + }, + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "cloud_resource_id": "Pipeline Identifier" + } + } + }, + { + "id": "sortBy", + "options": { + "fields": {}, + "sort": [ + { + "field": "Pipeline Identifier" + } + ] + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "transparent", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "mode": "gradient", + "type": "color-background" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #D" + }, + "properties": [ + { + "id": "displayName", + "value": "p50 Latency" + }, + { + "id": "color", + "value": { + "mode": "thresholds" + } + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 100 + }, + { + "color": "red", + "value": 1000 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #E" + }, + "properties": [ + { + "id": "displayName", + "value": "p95 Latency" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 100 + }, + { + "color": "red", + "value": 1000 + } + ] + } + }, + { + "id": "color" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #F" + }, + "properties": [ + { + "id": "displayName", + "value": "p99 Latency" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 100 + }, + { + "color": "red", + "value": 1000 + } + ] + } + }, + { + "id": "color" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "cloud_resource_id" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "", + "url": "/d/4f637c27-a19f-489e-a4af-719f1baa0a19/aio-service-dp-pipeline?orgId=1&${cluster:queryparam}&var-pipeline=${__data.fields[\"cloud_resource_id\"]}&${__url_time_range}" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 6 + }, + "id": 11, + "options": { + "cellHeight": "md", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "frameIndex": 0, + "showHeader": true + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "avg_over_time((histogram_quantile(0.95, sum(rate(aio_dp_pipeline_latency_bucket{cluster=\"$cluster\"}[$__rate_interval])) by (le, cloud_resource_id)) >= 0)[$__range:])", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "avg_over_time((histogram_quantile(0.95, sum(rate(aio_dp_pipeline_latency_bucket{cluster=\"$cluster\"}[$__rate_interval])) by (le, cloud_resource_id)) >= 0)[$__range:])", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "E" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "avg_over_time((histogram_quantile(0.99, sum(rate(aio_dp_pipeline_latency_bucket{cluster=\"$cluster\"}[$__rate_interval])) by (le, cloud_resource_id)) >= 0)[$__range:])", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "F" + } + ], + "title": "Pipeline Latencies", + "transformations": [ + { + "id": "merge", + "options": {} + }, + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "cloud_resource_id": "Pipeline Identifier" + } + } + }, + { + "id": "sortBy", + "options": { + "fields": {}, + "sort": [ + { + "field": "Pipeline Identifier" + } + ] + } + } + ], + "type": "table" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 4, + "panels": [], + "title": "Self Test", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 8, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# [Click for Detailed View of Self-test Pipeline](/d/4f637c27-a19f-489e-a4af-719f1baa0a19/aio-service-dp-pipeline?orgId=1&${cluster:queryparam}&var-pipeline=alice-springs%2Fself-test-pipeline&${__url_time_range})", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "broker_status" + }, + "properties": [ + { + "id": "mappings", + "value": [ + { + "options": { + "0": { + "color": "dark-red", + "index": 0, + "text": "No Messages" + } + }, + "type": "value" + }, + { + "options": { + "match": "null+nan", + "result": { + "color": "dark-yellow", + "index": 1, + "text": "Missing Metric" + } + }, + "type": "special" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 18 + }, + "id": 5, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": { + "titleSize": 29, + "valueSize": 120 + }, + "textMode": "value" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(increase(aio_dp_stage_incoming_messages{cluster=\"$cluster\",stage_type=~\"output/.*\", cloud_resource_id=~\".*self-test.*\"}[$__range]))", + "instant": true, + "interval": "", + "legendFormat": "{{label_name}}", + "refId": "A" + } + ], + "title": "Successful Self-Test messages", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "green", + "value": 0 + }, + { + "color": "#EAB839", + "value": 10 + }, + { + "color": "dark-orange", + "value": 100 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 18 + }, + "id": 6, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": { + "titleSize": 29, + "valueSize": 120 + }, + "textMode": "value" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(aio_dp_stage_outgoing_messages{stage_type=~\"messagestore/.*\", cloud_resource_id=~\".*self-test.*\"})", + "format": "table", + "hide": true, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(aio_dp_stage_incoming_messages{stage_type=~\"output/.*\", cloud_resource_id=~\".*self-test.*\"})", + "format": "table", + "hide": true, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "B" + }, + { + "datasource": { + "type": "__expr__", + "uid": "${DS_EXPRESSION}" + }, + "expression": "$A - $B", + "hide": false, + "refId": "C", + "type": "math" + } + ], + "title": "Failed Self-Test Messages", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 18 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "timezone": [ + "utc" + ], + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "histogram_quantile(0.99, sum by(le) (rate(aio_dp_pipeline_latency_bucket{cluster=\"$cluster\",cloud_resource_id=~\".*self-test.*\"}[$__rate_interval])))", + "instant": false, + "interval": "", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum by(le) (rate(aio_dp_pipeline_latency_bucket{cluster=\"$cluster\",cloud_resource_id=~\".*self-test.*\"}[$__rate_interval])))", + "hide": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.5, sum by(le) (rate(aio_dp_pipeline_latency_bucket{cluster=\"$cluster\",cloud_resource_id=~\".*self-test.*\"}[$__rate_interval])))", + "hide": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + } + ], + "title": "Self-Test Pipeline Latency", + "transparent": true, + "type": "timeseries" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 25 + }, + "id": 26, + "panels": [], + "title": "Checkpoints", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 26 + }, + "id": 19, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "timezone": [ + "utc" + ], + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(rate(aio_dp_runner_checkpoint_start{cluster=\"$cluster\"}[$__rate_interval]))", + "hide": true, + "instant": false, + "interval": "", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_runner_checkpoint_complete{cluster=\"$cluster\"}[$__rate_interval]))", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "__expr__", + "uid": "${DS_EXPRESSION}" + }, + "expression": "$A-$B", + "hide": false, + "refId": "C", + "type": "math" + } + ], + "title": "Incomplete checkpoints", + "transparent": true, + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 1e-13 + } + ] + }, + "unit": "err/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 8, + "y": 26 + }, + "id": 25, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_runner_checkpoint_error{cluster=\"$cluster\"}[$__rate_interval]))", + "legendFormat": "{{label_name}}", + "range": true, + "refId": "A" + } + ], + "title": "Checkpointing Errors", + "transformations": [ + { + "id": "merge", + "options": {} + }, + { + "id": "calculateField", + "options": { + "mode": "reduceRow", + "reduce": { + "include": [ + "Value" + ], + "reducer": "sum" + }, + "replaceFields": true + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 24, + "options": { + "orientation": "vertical", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "avg by(cloud_resource_id) (aio_dp_runner_checkpoint_size{cluster=\"$cluster\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Checkpoint size", + "type": "gauge" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 21, + "panels": [], + "title": "Heartbeats", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 35 + }, + "id": 22, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_reader_incoming_heartbeats{cluster=~\"$cluster\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Reader Generated Heartbeats", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 35 + }, + "id": 23, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_reader_processed_heartbeats{cluster=~\"$cluster\"}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Reader Processed Heartbeats", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 35 + }, + "id": 27, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_stage_heartbeats{cluster=~\"$cluster\"}[$__rate_interval]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Stage Processed Heartbeats", + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 43 + }, + "id": 3, + "panels": [], + "title": "Performance Metrics", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 10 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 1, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum by (pod) (rate(container_cpu_usage_seconds_total{cluster=\"$cluster\",container=~\"aio-dp-.*\"}[$__rate_interval]) * 100)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Pod CPU Usage (% of one CPU core)", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 256 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 52 + }, + "id": 2, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum by (pod) (container_memory_working_set_bytes{cluster=\"$cluster\",container=~\"aio-dp-.*\"} / (1024*1024))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Pod Memory Usage (MiB)", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-BlPu" + }, + "custom": { + "fillOpacity": 60, + "lineWidth": 1, + "spanNulls": 600000 + }, + "links": [], + "mappings": [ + { + "options": { + " ": { + "color": "transparent", + "index": 0 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 60 + }, + "id": 28, + "options": { + "alignValue": "center", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": true, + "rowHeight": 0.91, + "showValue": "auto", + "tooltip": { + "mode": "none", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "(\r\n sum(rate(aio_dp_reader_incoming_messages{cluster=~\"$cluster\"}[$__rate_interval])) by (container_image_tag, container_name) or on (container_name)\r\n clamp_max(absent(notExists{container_name=\"aio-dp-reader-worker\", container_image_tag=\" \"}),0)\r\n) or\r\n(\r\n sum(rate(aio_dp_runner_info{cluster=~\"$cluster\"}[$__rate_interval])) by (container_image_tag, container_name) or on (container_name)\r\n clamp_max(absent(notExists{container_name=\"aio-dp-runner-worker\", container_image_tag=\" \"}),0)\r\n) or\r\n(\r\n sum(rate(aio_dp_refdata_global_ingest_count{cluster=~\"$cluster\"}[$__rate_interval])) by (container_image_tag, container_name) or on (container_name)\r\n clamp_max(absent(notExists{container_name=\"aio-dp-refdata-store\", container_image_tag=\" \"}), 0)\r\n) or\r\n(\r\n sum(rate(aio_dp_reconcile_event{cluster=~\"$cluster\"}[$__rate_interval])) by (container_image_tag, container_name) or on (container_name)\r\n clamp_max(absent(notExists{container_name=\"manager\", container_image_tag=\" \"}), 0)\r\n)", + "format": "table", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + } + ], + "title": "Service Version", + "transformations": [ + { + "id": "groupingToMatrix", + "options": { + "columnField": "container_name", + "emptyValue": "empty", + "rowField": "Time", + "valueField": "container_image_tag" + } + }, + { + "id": "convertFieldType", + "options": { + "conversions": [ + { + "destinationType": "time", + "targetField": "Time\\container_name" + } + ], + "fields": {} + } + }, + { + "id": "sortBy", + "options": { + "fields": {}, + "sort": [ + { + "field": "Time\\container_name" + } + ] + } + } + ], + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "fillOpacity": 60, + "lineWidth": 1, + "spanNulls": 600000 + }, + "links": [], + "mappings": [ + { + "options": { + "0": { + "color": "transparent", + "index": 0 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 60 + }, + "id": 29, + "options": { + "alignValue": "center", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": true, + "rowHeight": 0.91, + "showValue": "auto", + "tooltip": { + "mode": "none", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "(\r\n count(count(container_cpu_usage_seconds_total{cluster=~\"$cluster\", container=\"aio-dp-reader-worker\"}) by (container, pod)) by (container) or on (container)\r\n clamp_max(absent(notExists{container=\"aio-dp-reader-worker\"}),0)\r\n) or\r\n(\r\n count(count(container_cpu_usage_seconds_total{cluster=~\"$cluster\", container=\"aio-dp-runner-worker\"}) by (container, pod)) by (container) or on (container)\r\n clamp_max(absent(notExists{container=\"aio-dp-runner-worker\"}),0)\r\n) or\r\n(\r\n count(count(container_cpu_usage_seconds_total{cluster=~\"$cluster\", container=\"aio-dp-refdata-store\"}) by (container, pod)) by (container) or on (container)\r\n clamp_max(absent(notExists{container=\"aio-dp-refdata-store\"}), 0)\r\n) or\r\n(\r\n count(count(container_cpu_usage_seconds_total{cluster=~\"$cluster\", container=\"manager\", pod=~\"aio-dp-.*\"}) by (container, pod)) by (container) or on (container)\r\n clamp_max(absent(notExists{container=\"manager\"}), 0)\r\n)", + "format": "table", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + } + ], + "title": "Service Pod Count", + "transformations": [ + { + "id": "groupingToMatrix", + "options": { + "columnField": "container", + "emptyValue": "empty", + "rowField": "Time", + "valueField": "Value" + } + }, + { + "id": "convertFieldType", + "options": { + "conversions": [ + { + "destinationType": "time", + "targetField": "Time\\container" + } + ], + "fields": {} + } + }, + { + "id": "sortBy", + "options": { + "fields": {}, + "sort": [ + { + "field": "Time\\container" + } + ] + } + } + ], + "type": "state-timeline" + } + ], + "refresh": "", + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "label_values(kube_node_status_condition,cluster)", + "hide": 0, + "includeAll": false, + "label": "Cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "label_values(kube_node_status_condition,cluster)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "aio-service-dp-overview", + "uid": "7fd56ac4-71cc-419c-9001-bc148b45a98c", + "version": 29, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-service-dp-pipeline-1698853686073.json b/samples/dashboard/grafana-dashboards/aio-service-dp-pipeline-1698853686073.json new file mode 100644 index 0000000..cba1255 --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-service-dp-pipeline-1698853686073.json @@ -0,0 +1,2615 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + }, + { + "name": "DS_EXPRESSION", + "label": "Expression", + "description": "", + "type": "datasource", + "pluginId": "__expr__" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "datasource", + "id": "__expr__", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 17, + "panels": [], + "title": "Reader Worker", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 1 + }, + "id": 18, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_reader_incoming_messages{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Input Messages", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 1 + }, + "id": 19, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_reader_processed_messages{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Messages Written to Message Store", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 1 + }, + "id": 21, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(aio_dp_reader_latency_bucket{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval])) by (le))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Reader Latency (95th Percentile)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 1e-13 + } + ] + }, + "unit": "err/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 18, + "y": 1 + }, + "id": 26, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_reader_errors{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Errors", + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 7 + }, + "id": 12, + "panels": [], + "title": "Runner Worker", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "transparent", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "mode": "gradient", + "type": "color-background" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Input Messages" + }, + "properties": [ + { + "id": "color", + "value": { + "mode": "continuous-blues" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Output Messages" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "continuous-blues" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Errors" + }, + "properties": [ + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "red", + "value": 1 + } + ] + } + }, + { + "id": "color" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #A" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #B" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #C" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "stage_id" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "", + "url": "/d/e6d7cca2-c5a9-4917-bf3b-43634132f009/aio-service-dp-stage?orgId=1&${pipeline:queryparam}&${__url_time_range}&var-stage=${__data.fields[\"stage_id\"]}" + } + ] + }, + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "displayName", + "value": "Stage ID" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "stage_index" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "stage_name" + }, + "properties": [ + { + "id": "noValue", + "value": "[Internal Message Store Reader]" + }, + { + "id": "displayName", + "value": "Stage Display Name" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "stage_type" + }, + "properties": [ + { + "id": "displayName", + "value": "Stage Type" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 15, + "options": { + "cellHeight": "md", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "frameIndex": 0, + "showHeader": true + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum((increase(aio_dp_stage_incoming_messages{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__range]))) by (stage_id, stage_type, stage_name, stage_index)", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum((increase(aio_dp_stage_outgoing_messages{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__range]))) by (stage_id, stage_type, stage_name, stage_index)", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum((increase(aio_dp_stage_errors{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__range]))) by (stage_id, stage_type, stage_name, stage_index)", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "C" + } + ], + "title": "Stage Throughputs", + "transformations": [ + { + "id": "merge", + "options": {} + }, + { + "id": "calculateField", + "options": { + "alias": "Input Messages", + "mode": "reduceRow", + "reduce": { + "include": [ + "Value #A" + ], + "reducer": "sum" + } + } + }, + { + "id": "calculateField", + "options": { + "alias": "Output Messages", + "mode": "reduceRow", + "reduce": { + "include": [ + "Value #B" + ], + "reducer": "sum" + } + } + }, + { + "id": "calculateField", + "options": { + "alias": "Errors", + "mode": "reduceRow", + "reduce": { + "include": [ + "Value #C" + ], + "reducer": "sum" + } + } + }, + { + "id": "sortBy", + "options": { + "fields": {}, + "sort": [ + { + "field": "stage_index" + } + ] + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "transparent", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "mode": "gradient", + "type": "color-background" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #D" + }, + "properties": [ + { + "id": "displayName", + "value": "p50 Latency" + }, + { + "id": "color", + "value": { + "mode": "thresholds" + } + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 10 + }, + { + "color": "orange", + "value": 100 + }, + { + "color": "red", + "value": 1000 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #E" + }, + "properties": [ + { + "id": "displayName", + "value": "p95 Latency" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 10 + }, + { + "color": "orange", + "value": 100 + }, + { + "color": "red", + "value": 1000 + } + ] + } + }, + { + "id": "color" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #F" + }, + "properties": [ + { + "id": "displayName", + "value": "p99 Latency" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 10 + }, + { + "color": "orange", + "value": 100 + }, + { + "color": "red", + "value": 1000 + } + ] + } + }, + { + "id": "color" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "stage_id" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "", + "url": "/d/e6d7cca2-c5a9-4917-bf3b-43634132f009/aio-service-dp-stage?orgId=1&${pipeline:queryparam}&${__url_time_range}&var-stage=${__data.fields[\"stage_id\"]}" + } + ] + }, + { + "id": "displayName", + "value": "Stage ID" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "stage_index" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "stage_name" + }, + "properties": [ + { + "id": "noValue", + "value": "[Internal Message Store Reader]" + }, + { + "id": "displayName", + "value": "Stage Display Name" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "stage_type" + }, + "properties": [ + { + "id": "displayName", + "value": "Stage Type" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 16, + "options": { + "cellHeight": "md", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "frameIndex": 0, + "showHeader": true + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "avg_over_time((histogram_quantile(0.50, sum(rate(aio_dp_stage_latency_bucket{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval])) by (le, stage_id, stage_type, stage_name, stage_index)) >= 0)[$__range:])", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "avg_over_time((histogram_quantile(0.95, sum(rate(aio_dp_stage_latency_bucket{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval])) by (le, stage_id, stage_type, stage_name, stage_index)) >= 0)[$__range:])", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "E" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "avg_over_time((histogram_quantile(0.99, sum(rate(aio_dp_stage_latency_bucket{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval])) by (le, stage_id, stage_type, stage_name, stage_index)) >= 0)[$__range:])", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "F" + } + ], + "title": "Stage Latencies", + "transformations": [ + { + "id": "merge", + "options": {} + }, + { + "id": "sortBy", + "options": { + "fields": {}, + "sort": [ + { + "field": "stage_index" + } + ] + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "transparent", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "mode": "gradient", + "type": "color-background" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Input Messages" + }, + "properties": [ + { + "id": "color", + "value": { + "mode": "continuous-blues" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Output Messages" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "continuous-blues" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Errors" + }, + "properties": [ + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "red", + "value": 1 + } + ] + } + }, + { + "id": "color" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #A" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #B" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #C" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "runner_partition" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "", + "url": "/d/04048dc7-ed13-449e-9ad2-206d99c1ae0c/aio-service-dp-runner?orgId=1&${pipeline:queryparam}&${cluster:queryparam}&${__url_time_range}&var-partitionId=${__data.fields[\"runner_partition\"]}" + } + ] + }, + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "displayName", + "value": "Partition ID" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 18 + }, + "id": 28, + "options": { + "cellHeight": "md", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "frameIndex": 0, + "showHeader": true + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(increase(aio_dp_stage_outgoing_messages{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\", stage_id=\"$$input\"}[$__range])) by (runner_partition)", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(increase(aio_dp_stage_incoming_messages{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\", stage_type=~\"^output/.*$\"}[$__range])) by (runner_partition)", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(increase(aio_dp_stage_errors{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__range])) by (runner_partition)", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "C" + } + ], + "title": "Runner Throughputs", + "transformations": [ + { + "id": "merge", + "options": {} + }, + { + "id": "calculateField", + "options": { + "alias": "Input Messages", + "mode": "reduceRow", + "reduce": { + "include": [ + "Value #A" + ], + "reducer": "sum" + } + } + }, + { + "id": "calculateField", + "options": { + "alias": "Output Messages", + "mode": "reduceRow", + "reduce": { + "include": [ + "Value #B" + ], + "reducer": "sum" + } + } + }, + { + "id": "calculateField", + "options": { + "alias": "Errors", + "mode": "reduceRow", + "reduce": { + "include": [ + "Value #C" + ], + "reducer": "sum" + } + } + }, + { + "id": "sortBy", + "options": { + "fields": {}, + "sort": [ + { + "field": "runner_partition" + } + ] + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "transparent", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "mode": "gradient", + "type": "color-background" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #D" + }, + "properties": [ + { + "id": "displayName", + "value": "p50 Latency" + }, + { + "id": "color", + "value": { + "mode": "thresholds" + } + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 100 + }, + { + "color": "red", + "value": 1000 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #E" + }, + "properties": [ + { + "id": "displayName", + "value": "p95 Latency" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 100 + }, + { + "color": "red", + "value": 1000 + } + ] + } + }, + { + "id": "color" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #F" + }, + "properties": [ + { + "id": "displayName", + "value": "p99 Latency" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 100 + }, + { + "color": "red", + "value": 1000 + } + ] + } + }, + { + "id": "color" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "runner_partition" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "", + "url": "/d/04048dc7-ed13-449e-9ad2-206d99c1ae0c/aio-service-dp-runner?orgId=1&${pipeline:queryparam}&${cluster:queryparam}&${__url_time_range}&var-partitionId=${__data.fields[\"runner_partition\"]}" + } + ] + }, + { + "id": "displayName", + "value": "Partition ID" + }, + { + "id": "unit" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 18 + }, + "id": 29, + "options": { + "cellHeight": "md", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "frameIndex": 0, + "showHeader": true + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "avg_over_time((histogram_quantile(0.50, sum(rate(aio_dp_pipeline_latency_bucket{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval])) by (le, runner_partition)) >= 0)[$__range:])", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "avg_over_time((histogram_quantile(0.95, sum(rate(aio_dp_pipeline_latency_bucket{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval])) by (le, runner_partition)) >= 0)[$__range:])", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "E" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "avg_over_time((histogram_quantile(0.99, sum(rate(aio_dp_pipeline_latency_bucket{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval])) by (le, runner_partition)) >= 0)[$__range:])", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "F" + } + ], + "title": "Runner E2E Latencies", + "transformations": [ + { + "id": "merge", + "options": {} + }, + { + "id": "sortBy", + "options": { + "fields": {}, + "sort": [ + { + "field": "runner_partition" + } + ] + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 28 + }, + "id": 27, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_stage_errors{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval])) by (stage_id, stage_type, error_code)", + "legendFormat": "{{error_code}}: {{stage_id}} ({{stage_type}})", + "range": true, + "refId": "A" + } + ], + "title": "Errors by Stage and Code", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 28 + }, + "id": 30, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_stage_errors{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval])) by (message_partition_key, error_code)", + "legendFormat": "{{error_code}}: {{stage_id}} ({{stage_type}})", + "range": true, + "refId": "A" + } + ], + "title": "Errors by Runner and Code", + "type": "timeseries" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 38 + }, + "id": 34, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue" + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 0, + "y": 1 + }, + "id": 2, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_reader_incoming_messages{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Input Messages", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue" + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 4, + "y": 1 + }, + "id": 3, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_stage_incoming_messages{cluster=\"$cluster\",stage_type=~\"output/.*\", cloud_resource_id=\"$pipeline\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Output Messages", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 1e-13 + } + ] + }, + "unit": "err/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 8, + "y": 1 + }, + "id": 24, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_stage_errors{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval]))", + "legendFormat": "{{label_name}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_reader_errors{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval]))", + "hide": false, + "legendFormat": "{{label_name}}", + "range": true, + "refId": "B" + } + ], + "title": "Processing Errors", + "transformations": [ + { + "id": "merge", + "options": {} + }, + { + "id": "calculateField", + "options": { + "mode": "reduceRow", + "reduce": { + "include": [ + "Value" + ], + "reducer": "sum" + }, + "replaceFields": true + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue" + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 12, + "y": 1 + }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(aio_dp_pipeline_latency_bucket{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval])) by (le))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "E2E Latency (95th Percentile)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 16, + "y": 1 + }, + "id": 6, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "count(count by (runner_partition) (rate(aio_dp_runner_info{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Runner Count", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 20, + "y": 1 + }, + "id": 7, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "count(count by (stage_id) (rate(aio_dp_stage_info{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Stage Count", + "type": "stat" + } + ], + "title": "Checkpointing", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 39 + }, + "id": 33, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_runner_checkpoint_start{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval]))", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_runner_checkpoint_complete{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval]))", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "__expr__", + "uid": "${DS_EXPRESSION}" + }, + "expression": "$A-$B", + "hide": false, + "refId": "C", + "type": "math" + } + ], + "title": "Incomplete checkpoints", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 8, + "y": 39 + }, + "id": 32, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_runner_checkpoint_error{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Checkpointing Errors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 39 + }, + "id": 31, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "avg by(cloud_resource_id) (aio_dp_runner_checkpoint_size{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Checkpoint Size", + "type": "gauge" + } + ], + "refresh": "", + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "label_values(kube_node_status_condition,cluster)", + "hide": 0, + "includeAll": false, + "label": "Cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "label_values(kube_node_status_condition,cluster)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "label_values(aio_dp_runner_info,cloud_resource_id)", + "hide": 0, + "includeAll": false, + "label": "Pipeline", + "multi": false, + "name": "pipeline", + "options": [], + "query": { + "query": "label_values(aio_dp_runner_info,cloud_resource_id)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "current": { + "selected": false, + "text": "1a05acfcbaa4a32eca05b6360a5fa1c1", + "value": "1a05acfcbaa4a32eca05b6360a5fa1c1" + }, + "description": "Trace id for interfacing with traces generated by the system", + "hide": 2, + "includeAll": false, + "label": "Runner Message Trace ID", + "multi": false, + "name": "runnerMessageTraceId", + "options": [], + "query": "", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + }, + { + "current": { + "selected": false, + "text": "", + "value": "" + }, + "description": "Trace id for interfacing with traces generated by the system", + "hide": 2, + "includeAll": false, + "label": "Runner Init Trace ID", + "multi": false, + "name": "runnerInitTraceId", + "options": [], + "query": "", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + }, + { + "current": { + "selected": false, + "text": "ec22752f680bf7995b92bca683646762", + "value": "ec22752f680bf7995b92bca683646762" + }, + "hide": 2, + "includeAll": false, + "label": "Reader Message Trace ID", + "multi": false, + "name": "readerMessageTraceId", + "options": [], + "query": "", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "aio-service-dp-pipeline", + "uid": "4f637c27-a19f-489e-a4af-719f1baa0a19", + "version": 13, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-service-dp-runner-1698853694635.json b/samples/dashboard/grafana-dashboards/aio-service-dp-runner-1698853694635.json new file mode 100644 index 0000000..4424675 --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-service-dp-runner-1698853694635.json @@ -0,0 +1,1642 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "sum(rate(aio_dp_stage_outgoing_messages{cluster=\"$cluster\", cloud_resource_id=\"$pipeline\", stage_id=\"$$input\", runner_partition=\"$partitionId\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Input Messages", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 4, + "y": 0 + }, + "id": 2, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "sum(rate(aio_dp_stage_incoming_messages{cluster=\"$cluster\", stage_type=~\"output/.*\", cloud_resource_id=\"$pipeline\", runner_partition=\"$partitionId\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Output Messages", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 1e-13 + } + ] + }, + "unit": "err/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 8, + "y": 0 + }, + "id": 3, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "sum(rate(aio_dp_stage_errors{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval]))", + "legendFormat": "{{label_name}}", + "range": true, + "refId": "A" + } + ], + "title": "Processing Errors", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 100 + }, + { + "color": "red", + "value": 1000 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 12, + "y": 0 + }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "histogram_quantile(0.95, sum by(le) (rate(aio_dp_pipeline_latency_bucket{cluster=\"$cluster\", cloud_resource_id=\"$pipeline\", runner_partition=\"$partitionId\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "E2E Latency (95th Percentile)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "destroying": { + "color": "yellow", + "index": 2 + }, + "initializing": { + "color": "blue", + "index": 1 + }, + "retrying": { + "color": "red", + "index": 3 + }, + "running": { + "color": "green", + "index": 0 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 16, + "y": 0 + }, + "id": 5, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "name" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "aio_dp_runner_info{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\", runner_partition=\"$partitionId\"}", + "format": "time_series", + "instant": true, + "legendFormat": "{{runner_state}}", + "range": false, + "refId": "A" + } + ], + "title": "Runner Status", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 20, + "y": 0 + }, + "id": 6, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "name" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "aio_dp_runner_info{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\", runner_partition=\"$partitionId\", }", + "format": "time_series", + "instant": true, + "legendFormat": "{{k8s_pod_name}}", + "range": false, + "refId": "A" + } + ], + "title": "Pod", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "transparent", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "mode": "gradient", + "type": "color-background" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Input Messages" + }, + "properties": [ + { + "id": "color", + "value": { + "mode": "continuous-blues" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Output Messages" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "continuous-blues" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Errors" + }, + "properties": [ + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "red", + "value": 1 + } + ] + } + }, + { + "id": "color" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #A" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #B" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #C" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "stage_id" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "", + "url": "/d/e6d7cca2-c5a9-4917-bf3b-43634132f009/aio-service-dp-stage?orgId=1&${pipeline:queryparam}&${__url_time_range}&var-stage=${__data.fields[\"stage_id\"]}" + } + ] + }, + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "displayName", + "value": "Stage ID" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "stage_index" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "stage_name" + }, + "properties": [ + { + "id": "noValue", + "value": "[Internal Message Store Reader]" + }, + { + "id": "displayName", + "value": "Stage Display Name" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "stage_type" + }, + "properties": [ + { + "id": "displayName", + "value": "Stage Type" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 5 + }, + "id": 7, + "options": { + "cellHeight": "md", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "frameIndex": 0, + "showHeader": true + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "exemplar": false, + "expr": "sum by(stage_id, stage_type, stage_name, stage_index) (increase(aio_dp_stage_incoming_messages{cluster=\"$cluster\", cloud_resource_id=\"$pipeline\", runner_partition=\"$partitionId\"}[$__range])) * on(stage_id) aio_dp_stage_info{cluster=\"$cluster\", cloud_resource_id=\"$pipeline\", runner_partition=\"$partitionId\"}", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "exemplar": false, + "expr": "sum by(stage_id, stage_type, stage_name, stage_index) (increase(aio_dp_stage_outgoing_messages{cluster=\"$cluster\", cloud_resource_id=\"$pipeline\", runner_partition=\"$partitionId\"}[$__range])) * on(stage_id) aio_dp_stage_info{cluster=\"$cluster\", cloud_resource_id=\"$pipeline\", runner_partition=\"$partitionId\"}", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "exemplar": false, + "expr": "sum by(stage_id, stage_type, stage_name, stage_index) (increase(aio_dp_stage_errors{cluster=\"$cluster\", cloud_resource_id=\"$pipeline\", runner_partition=\"$partitionId\"}[$__range])) * on(stage_id) aio_dp_stage_info{cluster=\"$cluster\", cloud_resource_id=\"$pipeline\", runner_partition=\"$partitionId\"}", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "C" + } + ], + "title": "Stage Throughputs", + "transformations": [ + { + "id": "merge", + "options": {} + }, + { + "id": "calculateField", + "options": { + "alias": "Input Messages", + "mode": "reduceRow", + "reduce": { + "include": [ + "Value #A" + ], + "reducer": "sum" + } + } + }, + { + "id": "calculateField", + "options": { + "alias": "Output Messages", + "mode": "reduceRow", + "reduce": { + "include": [ + "Value #B" + ], + "reducer": "sum" + } + } + }, + { + "id": "calculateField", + "options": { + "alias": "Errors", + "mode": "reduceRow", + "reduce": { + "include": [ + "Value #C" + ], + "reducer": "sum" + } + } + }, + { + "id": "sortBy", + "options": { + "fields": {}, + "sort": [ + { + "field": "stage_index" + } + ] + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "transparent", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "mode": "gradient", + "type": "color-background" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #D" + }, + "properties": [ + { + "id": "displayName", + "value": "p50 Latency" + }, + { + "id": "color", + "value": { + "mode": "thresholds" + } + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 10 + }, + { + "color": "orange", + "value": 100 + }, + { + "color": "red", + "value": 1000 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #E" + }, + "properties": [ + { + "id": "displayName", + "value": "p95 Latency" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 10 + }, + { + "color": "orange", + "value": 100 + }, + { + "color": "red", + "value": 1000 + } + ] + } + }, + { + "id": "color" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #F" + }, + "properties": [ + { + "id": "displayName", + "value": "p99 Latency" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 10 + }, + { + "color": "orange", + "value": 100 + }, + { + "color": "red", + "value": 1000 + } + ] + } + }, + { + "id": "color" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "stage_id" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "", + "url": "/d/e6d7cca2-c5a9-4917-bf3b-43634132f009/aio-service-dp-stage?orgId=1&${pipeline:queryparam}&${__url_time_range}&var-stage=${__data.fields[\"stage_id\"]}" + } + ] + }, + { + "id": "displayName", + "value": "Stage ID" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "stage_index" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "stage_name" + }, + "properties": [ + { + "id": "noValue", + "value": "[Internal Message Store Reader]" + }, + { + "id": "displayName", + "value": "Stage Display Name" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "stage_type" + }, + "properties": [ + { + "id": "displayName", + "value": "Stage Type" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #A" + }, + "properties": [ + { + "id": "displayName", + "value": "Average Latency" + }, + { + "id": "color" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 10 + }, + { + "color": "orange", + "value": 100 + }, + { + "color": "red", + "value": 1000 + } + ] + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 5 + }, + "id": 8, + "options": { + "cellHeight": "md", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "frameIndex": 0, + "showHeader": true + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "avg_over_time((histogram_quantile(0.50, sum(rate(aio_dp_stage_latency_bucket{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval])) by (le, stage_id, stage_type, stage_name, stage_index)) >= 0)[$__range:])", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "avg_over_time((histogram_quantile(0.95, sum(rate(aio_dp_stage_latency_bucket{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\", runner_partition=\"$partitionId\"}[$__rate_interval])) by (le, stage_id, stage_type, stage_name, stage_index)) >= 0)[$__range:])", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "E" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "avg_over_time((histogram_quantile(0.99, sum(rate(aio_dp_stage_latency_bucket{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\", runner_partition=\"$partitionId\"}[$__rate_interval])) by (le, stage_id, stage_type, stage_name, stage_index)) >= 0)[$__range:])", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "F" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "avg_over_time((avg(rate(aio_dp_stage_latency_sum{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval]) / rate(aio_dp_stage_latency_count{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\"}[$__rate_interval])) by (stage_id, stage_type, stage_name, stage_index) >= 0)[$__range:])", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Stage Latencies", + "transformations": [ + { + "id": "merge", + "options": {} + }, + { + "id": "sortBy", + "options": { + "fields": {}, + "sort": [ + { + "field": "stage_index" + } + ] + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 20 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 15 + }, + "id": 14, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.5.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "histogram_quantile(0.5, sum by(le) (rate(aio_dp_pipeline_latency_bucket{cluster=\"$cluster\", cloud_resource_id=\"$pipeline\", runner_partition=\"$partitionId\"}[$__rate_interval])))", + "legendFormat": "p50", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "histogram_quantile(0.95, sum by(le) (rate(aio_dp_pipeline_latency_bucket{cluster=\"$cluster\", cloud_resource_id=\"$pipeline\", runner_partition=\"$partitionId\"}[$__rate_interval])))", + "hide": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "histogram_quantile(0.99, sum by(le) (rate(aio_dp_pipeline_latency_bucket{cluster=\"$cluster\", cloud_resource_id=\"$pipeline\", runner_partition=\"$partitionId\"}[$__rate_interval])))", + "hide": false, + "legendFormat": "p99", + "range": true, + "refId": "C" + } + ], + "title": "Runner E2E Latency", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 6, + "x": 12, + "y": 15 + }, + "id": 15, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum by(le) (rate(aio_dp_runner_input_stage_blocked_time_ratio_bucket{cluster=\"$cluster\", cloud_resource_id=\"$pipeline\", runner_partition=\"$partitionId\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Source Stage Blocked by Upstream", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 6, + "x": 18, + "y": 15 + }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "sum by(stage_id, stage_type, error_code) (rate(aio_dp_stage_errors{cluster=\"$cluster\", cloud_resource_id=\"$pipeline\", runner_partition=\"$partitionId\"}[$__rate_interval]))", + "legendFormat": "{{error_code}}: {{stage_id}} ({{stage_type}})", + "range": true, + "refId": "A" + } + ], + "title": "Errors by Stage and Code", + "type": "timeseries" + } + ], + "refresh": "", + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "label_values(kube_node_status_condition,cluster)", + "hide": 0, + "includeAll": false, + "label": "Cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "label_values(kube_node_status_condition,cluster)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "label_values(aio_dp_runner_info,cloud_resource_id)", + "hide": 0, + "includeAll": false, + "label": "Pipeline", + "multi": false, + "name": "pipeline", + "options": [], + "query": { + "query": "label_values(aio_dp_runner_info,cloud_resource_id)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "label_values(aio_dp_runner_info,runner_partition)", + "hide": 0, + "includeAll": false, + "label": "Partition ID", + "multi": false, + "name": "partitionId", + "options": [], + "query": { + "query": "label_values(aio_dp_runner_info,runner_partition)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": { + "selected": false, + "text": "2cd08bf9162cbab6976343587a52c259", + "value": "2cd08bf9162cbab6976343587a52c259" + }, + "description": "Trace id for interfacing with traces generated by the system", + "hide": 2, + "includeAll": false, + "label": "Runner Message Trace ID", + "multi": false, + "name": "runnerMessageTraceId", + "options": [], + "query": "", + "skipUrlSync": false, + "type": "custom" + }, + { + "current": {}, + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "runnerInitTraceId", + "options": [], + "query": "", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "aio-service-dp-runner", + "uid": "04048dc7-ed13-449e-9ad2-206d99c1ae0c", + "version": 13, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-service-dp-stage-1698853700645.json b/samples/dashboard/grafana-dashboards/aio-service-dp-stage-1698853700645.json new file mode 100644 index 0000000..763970b --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-service-dp-stage-1698853700645.json @@ -0,0 +1,1073 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 0, + "y": 0 + }, + "id": 11, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "name" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "max(aio_dp_stage_info{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\", stage_id=\"$stage\"}) by (stage_name)", + "instant": true, + "legendFormat": "{{stage_name}}", + "range": false, + "refId": "A" + } + ], + "title": "Stage Display Name", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 4, + "y": 0 + }, + "id": 12, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "name" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "max(aio_dp_stage_info{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\", stage_id=\"$stage\"}) by (stage_type)", + "instant": true, + "legendFormat": "{{stage_type}}", + "range": false, + "refId": "A" + } + ], + "title": "Stage Type", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 8, + "y": 0 + }, + "id": 1, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_stage_incoming_messages{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\", stage_id=\"$stage\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Incoming Messages", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 12, + "y": 0 + }, + "id": 2, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_stage_outgoing_messages{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\", stage_id=\"$stage\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Outgoing Messages", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 1e-11 + } + ] + }, + "unit": "err/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 16, + "y": 0 + }, + "id": 3, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_stage_errors{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\", stage_id=\"$stage\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Errors", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 10 + }, + { + "color": "orange", + "value": 100 + }, + { + "color": "red", + "value": 1000 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 20, + "y": 0 + }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(aio_dp_stage_latency_bucket{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\", stage_id=\"$stage\"}[$__rate_interval])) by (le))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "P95 Latency", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 5 + }, + "id": 5, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.5.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_stage_incoming_messages{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\", stage_id=\"$stage\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Incoming Messages", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 5 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.5.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_stage_outgoing_messages{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\", stage_id=\"$stage\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Outgoing Messages", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 20 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 15 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.5.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, sum(rate(aio_dp_stage_latency_bucket{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\", stage_id=\"$stage\"}[$__rate_interval])) by (le))", + "legendFormat": "p50", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum(rate(aio_dp_stage_latency_bucket{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\", stage_id=\"$stage\"}[$__rate_interval])) by (le))", + "hide": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(aio_dp_stage_latency_bucket{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\", stage_id=\"$stage\"}[$__rate_interval])) by (le))", + "hide": false, + "legendFormat": "p99", + "range": true, + "refId": "C" + } + ], + "title": "Stage Latency", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "green", + "value": 0 + }, + { + "color": "#EAB839", + "value": 50 + }, + { + "color": "red", + "value": 100 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 15 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "avg by (runner_partition) (rate(aio_dp_stage_latency_sum{cluster=\"$cluster\", cloud_resource_id=\"$pipeline\", stage_id=\"$stage\"}[$__rate_interval])) / 1000 ", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Percent Active Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 1e-9 + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 25 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.5.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_dp_stage_errors{cluster=\"$cluster\",cloud_resource_id=\"$pipeline\", stage_id=\"$stage\"}[$__rate_interval])) by (error_code)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Errors by Code", + "transformations": [], + "type": "timeseries" + } + ], + "refresh": "", + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "label_values(kube_node_status_condition,cluster)", + "hide": 0, + "includeAll": false, + "label": "Cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "label_values(kube_node_status_condition,cluster)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "label_values(aio_dp_runner_info,cloud_resource_id)", + "hide": 0, + "includeAll": false, + "label": "Pipeline", + "multi": false, + "name": "pipeline", + "options": [], + "query": { + "query": "label_values(aio_dp_runner_info,cloud_resource_id)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "label_values(aio_dp_stage_info,stage_id)", + "hide": 0, + "includeAll": false, + "label": "Stage", + "multi": false, + "name": "stage", + "options": [], + "query": { + "query": "label_values(aio_dp_stage_info,stage_id)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": { + "selected": false, + "text": "5c3062669fcf0a2f6ca6b7aa8bdcc433", + "value": "5c3062669fcf0a2f6ca6b7aa8bdcc433" + }, + "hide": 2, + "includeAll": false, + "multi": false, + "name": "stageMessageTraceId", + "options": [], + "query": "", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "aio-service-dp-stage", + "uid": "e6d7cca2-c5a9-4917-bf3b-43634132f009", + "version": 9, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-service-lnm-1698853706938.json b/samples/dashboard/grafana-dashboards/aio-service-lnm-1698853706938.json new file mode 100644 index 0000000..a850fbc --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-service-lnm-1698853706938.json @@ -0,0 +1,1864 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + }, + { + "name": "DS_AZURE_MONITOR", + "label": "Azure Monitor", + "description": "", + "type": "datasource", + "pluginId": "grafana-azure-monitor-datasource", + "pluginName": "Azure Monitor" + }, + { + "name": "VAR_COMPONENT", + "type": "constant", + "label": "component", + "value": "^(aio-lnm-).*", + "description": "" + }, + { + "name": "VAR_COMPONENT_TEXT", + "type": "constant", + "label": "component_text", + "value": "LNM", + "description": "" + }, + { + "name": "VAR_LATENCY_PERCENTILE", + "type": "constant", + "label": "latency_percentile", + "value": "0.95", + "description": "" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "grafana-azure-monitor-datasource", + "name": "Azure Monitor", + "version": "1.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 8, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n Azure Edge Services - ${component_text} Health\n
\n
\n   Scenario Health (SLO/RUM) related to ${component_text}\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "The cumulative uptime should always increase. If decreases sow ", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "links": [ + { + "targetBlank": true, + "title": "Show details for ${component_text} ${__field.labels._}", + "url": "${__field.labels.url}?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#7f7f7f", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "mappings", + "value": [ + { + "options": { + "from": 0, + "result": { + "color": "green", + "index": 0, + "text": "Healthy" + }, + "to": 15 + }, + "type": "range" + }, + { + "options": { + "match": "null+nan", + "result": { + "color": "yellow", + "index": 1, + "text": "Unhealthy" + } + }, + "type": "special" + }, + { + "options": { + "from": -1, + "result": { + "color": "red", + "index": 2, + "text": "Unhealthy" + }, + "to": 0 + }, + "type": "range" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 62, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum without(custom_resource_name, level, podname, instance, job, level) (rate(server_uptime{cluster=\"$cluster\", service_name=\"aio_lnm\"}[10m]))", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + } + ], + "title": "LNM Service Health", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 12, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Golden Metrics\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMax": 101, + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Overall" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 4 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 12 + }, + "id": 66, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum without (level, custom_resource_name, instance, job, podname) (server_total_connections{service_name=\"aio_lnm\", cluster=\"$cluster\"})", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Total Connections", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMax": 101, + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Overall" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 4 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 20 + }, + "id": 51, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum without (custom_resource_name, envoy_tcp_prefix, instance, job, level,podname) (rate(tcp_downstream_cx_rx_bytes_total{service_name=\"aio_lnm\", cluster=\"$cluster\"}[5m]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Rate of Data sent to upper level", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMax": 101, + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Overall" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 4 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 20 + }, + "id": 67, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum without (custom_resource_name, envoy_tcp_prefix, instance, job, level,podname) (rate(tcp_downstream_cx_tx_bytes_total{service_name=\"aio_lnm\", cluster=\"$cluster\"}[5m]))", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Rate of Data received from upper level", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Total number of times TLS was found.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".*s$" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisLabel", + "value": "total count" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*[/]sec[)]$" + }, + "properties": [ + { + "id": "custom.axisLabel", + "value": "throughput (msgs/sec)" + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.scaleDistribution", + "value": { + "log": 10, + "type": "symlog" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 28 + }, + "id": 64, + "links": [ + { + "targetBlank": true, + "title": "TLS Inspector stats", + "url": "https://www.envoyproxy.io/docs/envoy/latest/configuration/listeners/listener_filters/tls_inspector#statistics" + } + ], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "tls_inspector_tls_found{cluster=\"$cluster\", service_name=\"aio_lnm\"}", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "TLS Inspector TLS found", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Total number of times TLS was not found", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 28 + }, + "id": 65, + "links": [ + { + "targetBlank": true, + "title": "TLS Inspector stats", + "url": "https://www.envoyproxy.io/docs/envoy/latest/configuration/listeners/listener_filters/tls_inspector#statistics" + } + ], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "tls_inspector_tls_not_found{cluster=\"$cluster\",service_name=\"aio_lnm\"}", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "TLS Inspector TLS Not Found", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Total number of times Server Name Indication was found", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".*s$" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisLabel", + "value": "total count" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*[/]sec[)]$" + }, + "properties": [ + { + "id": "custom.axisLabel", + "value": "throughput (msgs/sec)" + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.scaleDistribution", + "value": { + "log": 10, + "type": "symlog" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 36 + }, + "id": 50, + "links": [ + { + "targetBlank": true, + "title": "TLS Inspector stats", + "url": "https://www.envoyproxy.io/docs/envoy/latest/configuration/listeners/listener_filters/tls_inspector#statistics" + } + ], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "tls_inspector_sni_found{cluster=\"$cluster\", podname=~\"$component\"}", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "TLS Inspector SNI found", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Total number of times Server Name Indication was not found.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 63, + "links": [ + { + "targetBlank": true, + "title": "TLS Inspector stats", + "url": "https://www.envoyproxy.io/docs/envoy/latest/configuration/listeners/listener_filters/tls_inspector#statistics" + } + ], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "tls_inspector_sni_not_found{cluster=\"$cluster\", podname=~\"$component\"}", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "TLS Inspector SNI Not Found", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 11, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Infrastructure Workload Health\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "CPU usage of LNM pods in millicore", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "milli-cores", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels.pod}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels.pod}" + } + ], + "mappings": [ + { + "options": { + "match": "null+nan", + "result": { + "color": "transparent", + "index": 0 + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Overall" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 46 + }, + "id": 56, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum by (pod) (rate(container_cpu_usage_seconds_total{pod=~\"$component\", cluster=\"$cluster\"}[$__rate_interval]) * 1000)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "CPU Usage by Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "working bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels.pod}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels.pod}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 46 + }, + "id": 57, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum by (pod) (container_memory_working_set_bytes{cluster=\"$cluster\",namespace=~\".*\", pod=~\"$component\", container!=\"\"}/(1024*1024))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Memory Usage by Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 54 + }, + "id": 13, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Errors & Logs\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "description": "work in progress", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "yellow", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": true + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "yellow" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PodName" + }, + "properties": [ + { + "id": "custom.width", + "value": 300 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Reason" + }, + "properties": [ + { + "id": "custom.width", + "value": 213 + }, + { + "id": "custom.align", + "value": "center" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "Failed": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ] + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "custom.align", + "value": "left" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Count" + }, + "properties": [ + { + "id": "custom.width", + "value": 102 + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "color", + "value": { + "mode": "continuous-BlPu" + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.width", + "value": 200 + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Message" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "TenantId" + }, + "properties": [ + { + "id": "custom.width", + "value": 343 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Computer" + }, + "properties": [ + { + "id": "custom.width", + "value": 348 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 56 + }, + "id": 55, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "LastSeen" + } + ] + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "azureLogAnalytics": { + "query": "KubeEvents\r\n| where TimeGenerated > $__timeFrom() and TimeGenerated <= $__timeTo\r\n| where ClusterName == '$cluster'\r\n| order by LastSeen desc, FirstSeen desc, TimeGenerated desc\r\n| project-rename PodName = Name\r\n| project FirstSeen, LastSeen, Count, PodName, Reason, Message\r\n| take 10", + "resources": [ + "/subscriptions/af342bf1-1ace-41df-902c-47921400551b" + ], + "resultFormat": "table" + }, + "azureMonitor": { + "allowedTimeGrainsMs": [], + "timeGrain": "auto" + }, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "queryType": "Azure Log Analytics", + "refId": "A" + } + ], + "title": "Last 10 Kube Events entries (from $cluster)", + "type": "table" + } + ], + "refresh": "1m", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "description": "Defines the service Component this report focuses on.", + "hide": 2, + "name": "component", + "query": "${VAR_COMPONENT}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_COMPONENT}", + "text": "${VAR_COMPONENT}", + "selected": false + }, + "options": [ + { + "value": "${VAR_COMPONENT}", + "text": "${VAR_COMPONENT}", + "selected": false + } + ] + }, + { + "description": "Defines the service Component this report focuses on.", + "hide": 2, + "name": "component_text", + "query": "${VAR_COMPONENT_TEXT}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_COMPONENT_TEXT}", + "text": "${VAR_COMPONENT_TEXT}", + "selected": false + }, + "options": [ + { + "value": "${VAR_COMPONENT_TEXT}", + "text": "${VAR_COMPONENT_TEXT}", + "selected": false + } + ] + }, + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_node_status_condition", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "kube_node_status_condition", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*cluster=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "hide": 0, + "includeAll": true, + "multi": true, + "name": "namespace", + "options": [], + "query": { + "query": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "hide": 2, + "name": "latency_percentile", + "query": "${VAR_LATENCY_PERCENTILE}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_LATENCY_PERCENTILE}", + "text": "${VAR_LATENCY_PERCENTILE}", + "selected": false + }, + "options": [ + { + "value": "${VAR_LATENCY_PERCENTILE}", + "text": "${VAR_LATENCY_PERCENTILE}", + "selected": false + } + ] + }, + { + "auto": true, + "auto_count": 30, + "auto_min": "10s", + "current": { + "selected": false, + "text": "auto", + "value": "$__auto_interval_latency_quantile_range" + }, + "hide": 2, + "name": "latency_quantile_range", + "options": [ + { + "selected": true, + "text": "auto", + "value": "$__auto_interval_latency_quantile_range" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "15m", + "value": "15m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "3h", + "value": "3h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + } + ], + "query": "5m,10m,15m,1h,3h,6h", + "queryValue": "", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + } + ] + }, + "time": { + "from": "now-2d", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "aio-service-lnm", + "uid": "da8b502b-0f79-458b-91e3-1efb977ab389", + "version": 10, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-service-mq-Current traffic (includes selftest traffic)-1698853748637.json b/samples/dashboard/grafana-dashboards/aio-service-mq-Current traffic (includes selftest traffic)-1698853748637.json new file mode 100644 index 0000000..929c1b0 --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-service-mq-Current traffic (includes selftest traffic)-1698853748637.json @@ -0,0 +1,576 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 2, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "dark-orange", + "mode": "continuous-BlYlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Inbound messages / s" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.1.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": true, + "expr": "sum(rate(aio_mq_publishes_received{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Inbound messages / s", + "range": true, + "refId": "A" + } + ], + "title": "Inbound messages / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "noValue": "null", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 7, + "x": 8, + "y": 0 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.1.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": true, + "expr": "sum(rate(aio_mq_publishes_sent{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[$__rate_interval]))", + "hide": false, + "interval": "", + "legendFormat": "Outbound messages / s", + "range": true, + "refId": "B" + } + ], + "title": "Outbound messages / s", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "light-yellow", + "mode": "fixed" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Connected sessions" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 6 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.1.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": true, + "expr": "sum(aio_mq_connected_sessions{hostname=~\".*frontend.*\", cluster=~\"$cluster\", instance=~\"$namespace\"})", + "interval": "", + "legendFormat": "Connected sessions", + "range": true, + "refId": "total_sessions" + } + ], + "title": "Connected sessions", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "light-red", + "mode": "fixed" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Topic subscriptions" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 7, + "x": 8, + "y": 6 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.1.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": true, + "expr": "sum(aio_mq_total_subscriptions{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"})", + "interval": "", + "legendFormat": "Topic subscriptions", + "range": true, + "refId": "total_num_subscriptions" + } + ], + "title": "Topic subscriptions", + "type": "timeseries" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_node_status_condition", + "description": "PAS Cluster to view", + "hide": 0, + "includeAll": false, + "label": "Cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "kube_node_status_condition", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*cluster=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "hide": 0, + "includeAll": true, + "multi": true, + "name": "namespace", + "options": [], + "query": { + "query": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "aio-service-mq-Current traffic (includes selftest traffic)", + "uid": "f4606347-5cfb-47ce-adf5-06f7810a9863", + "version": 5, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-service-mq-bridges-1698853739458.json b/samples/dashboard/grafana-dashboards/aio-service-mq-bridges-1698853739458.json new file mode 100644 index 0000000..e1b81e9 --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-service-mq-bridges-1698853739458.json @@ -0,0 +1,575 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 2, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Nb connections to local broker" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 5, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "repeat": "bridge", + "repeatDirection": "v", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_active_connections_count{type=\"local\", pod_id=\"$bridge\", cluster=~\"$cluster\", instance=~\"$namespace\"}", + "legendFormat": "Nb connections to local broker", + "range": true, + "refId": "A" + } + ], + "title": "Connections to local broker ($bridge)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Nb connections to remote broker" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 5, + "x": 5, + "y": 0 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "repeat": "bridge", + "repeatDirection": "v", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_active_connections_count{type=\"remote\", pod_id=\"$bridge\", cluster=~\"$cluster\", instance=~\"$namespace\"}", + "legendFormat": "Nb connections to remote broker", + "range": true, + "refId": "A" + } + ], + "title": "Connections to remote broker ($bridge)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Nb of routes" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 5, + "x": 10, + "y": 0 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "repeat": "bridge", + "repeatDirection": "v", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_number_of_routes{pod_id=\"$bridge\", cluster=~\"$cluster\", instance=~\"$namespace\"}", + "legendFormat": "Nb of routes", + "range": true, + "refId": "A" + } + ], + "title": "Number of routes ($bridge)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 5, + "x": 15, + "y": 0 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "repeat": "bridge", + "repeatDirection": "v", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_publishes_processed{pod_id=\"$bridge\", cluster=~\"$cluster\", instance=~\"$namespace\"}", + "legendFormat": "{{direction}}", + "range": true, + "refId": "A" + } + ], + "title": "Publishes processed ($bridge)", + "type": "timeseries" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "definition": "active_connections_count", + "hide": 2, + "includeAll": true, + "multi": true, + "name": "bridge", + "options": [], + "query": { + "query": "active_connections_count", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "/.*pod_id=\"(?[^\"]+)/g", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_node_status_condition", + "description": "PAS Cluster to view", + "hide": 0, + "includeAll": false, + "label": "Cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "kube_node_status_condition", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*cluster=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "hide": 0, + "includeAll": true, + "multi": true, + "name": "namespace", + "options": [], + "query": { + "query": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "aio-service-mq-bridges", + "uid": "ad4d5b3e-4c41-4dc9-baf4-25466a67673c", + "version": 5, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-service-mq-main-1698853755082.json b/samples/dashboard/grafana-dashboards/aio-service-mq-main-1698853755082.json new file mode 100644 index 0000000..1dd4e44 --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-service-mq-main-1698853755082.json @@ -0,0 +1,1586 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 2, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 78, + "panels": [], + "title": "Latency (selftest traffic only)", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "links": [ + { + "targetBlank": true, + "title": "", + "url": "d/bf5237d2-7deb-4144-aa46-41e1c1629b30/aio-service-mq-publish?orgId=1" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 1 + }, + "id": 113, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_publish_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Avg publish latency [ms] (99th pctl)", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "links": [ + { + "targetBlank": true, + "title": "", + "url": "d/bf5237d2-7deb-4144-aa46-41e1c1629b30/aio-service-mq-publish?orgId=1" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 1 + }, + "id": 170, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_publish_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Std dev publish latency [ms] (99th pctl)", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "links": [ + { + "targetBlank": true, + "title": "", + "url": "d/c58ee063-e5f3-4829-ae8f-0160127759cc/aio-service-mq-ping?orgId=1" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 4 + }, + "id": 180, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_ping_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Avg ping latency [ms] (99th pctl)", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "links": [ + { + "targetBlank": true, + "title": "", + "url": "d/c58ee063-e5f3-4829-ae8f-0160127759cc/aio-service-mq-ping?orgId=1" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 4 + }, + "id": 181, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_ping_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Std dev ping latency [ms] (99th pctl)", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "links": [ + { + "targetBlank": true, + "title": "", + "url": "d/b5d606dc-a841-4ec0-b7c5-4f1d37c4e877/aio-service-mq-subscribe?orgId=1" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 7 + }, + "id": 165, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_subscribe_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Avg subscribe latency [ms] (99th pctl)", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "links": [ + { + "targetBlank": true, + "title": "", + "url": "d/b5d606dc-a841-4ec0-b7c5-4f1d37c4e877/aio-service-mq-subscribe?orgId=1" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 7 + }, + "id": 168, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_subscribe_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Std dev subscribe latency [ms] (99th pctl)", + "transformations": [], + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 88, + "panels": [], + "title": "Health (selftest traffic only)", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "links": [ + { + "targetBlank": true, + "title": "", + "url": "d/f41cdbe5-4075-4f05-aeb2-a34b5b46571c/aio-service-mq-connect?orgId=1" + } + ], + "mappings": [], + "max": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "#EAB839", + "value": 0.8 + }, + { + "color": "blue", + "value": 0.98 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 11 + }, + "id": 171, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "/^Value$/", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_connect_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "format": "table", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Last connect health [%]", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Total number of MQ pods", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "links": [ + { + "targetBlank": true, + "title": "", + "url": "d/eb3949b9-da3a-4b9e-8573-beb5507617a9/aio-service-mq-clusterperf?orgId=1&var-pod=All" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 11 + }, + "id": 178, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "count(kube_pod_info{pod=~\"aio-mq.*\",cluster=~\"$cluster\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Total number of pods", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "links": [ + { + "targetBlank": true, + "title": "", + "url": "d/bf5237d2-7deb-4144-aa46-41e1c1629b30/aio-service-mq-publish?orgId=1" + } + ], + "mappings": [], + "max": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "#EAB839", + "value": 0.8 + }, + { + "color": "blue", + "value": 0.98 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 14 + }, + "id": 172, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "/^Value$/", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_publish_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "format": "table", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Last publish health [%]", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "links": [ + { + "targetBlank": true, + "title": "", + "url": "d/eb3949b9-da3a-4b9e-8573-beb5507617a9/aio-service-mq-clusterperf?orgId=1&var-pod=All" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + }, + { + "color": "red", + "value": 1 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 14 + }, + "id": 175, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "count(sum by (pod) (container_memory_working_set_bytes{pod=~\"aio-mq.*\", container!=\"\", cluster=~\"$cluster\", instance=~\"$namespace\"} / (1024*1024)) > 300) or vector(0)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Pods with high memory (300 MiB or more)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "links": [ + { + "targetBlank": true, + "title": "", + "url": "d/c58ee063-e5f3-4829-ae8f-0160127759cc/aio-service-mq-ping?orgId=1" + } + ], + "mappings": [], + "max": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "#EAB839", + "value": 0.8 + }, + { + "color": "blue", + "value": 0.98 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 17 + }, + "id": 179, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "/^Value$/", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_ping_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "format": "table", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Last ping health [%]", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "links": [ + { + "targetBlank": true, + "title": "", + "url": "d/eb3949b9-da3a-4b9e-8573-beb5507617a9/aio-service-mq-clusterperf?orgId=1&var-pod=All" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + }, + { + "color": "red", + "value": 1 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 17 + }, + "id": 176, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "count(sum by (pod) (rate(container_cpu_usage_seconds_total{pod=~\"aio-mq.*\", cluster=~\"$cluster\", instance=~\"$namespace\"}[$__rate_interval]) * 1000) > 5) or vector(0)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Pods with high CPU (5 millicores or more)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "links": [ + { + "targetBlank": true, + "title": "", + "url": "d/b5d606dc-a841-4ec0-b7c5-4f1d37c4e877/aio-service-mq-subscribe?orgId=1" + } + ], + "mappings": [], + "max": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "#EAB839", + "value": 0.8 + }, + { + "color": "blue", + "value": 0.98 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 20 + }, + "id": 173, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "/^Value$/", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_subscribe_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "format": "table", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Last subscribe health [%]", + "transformations": [], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "links": [ + { + "targetBlank": true, + "title": "", + "url": "d/eb3949b9-da3a-4b9e-8573-beb5507617a9/aio-service-mq-clusterperf?orgId=1&var-pod=All" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + }, + { + "color": "red", + "value": 1 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 20 + }, + "id": 177, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "count(sum by (pod)(changes(kube_pod_status_ready{pod=~\"aio-mq.*\",condition=\"true\", cluster=~\"$cluster\", instance=~\"$namespace\"}[5m])) > 5) or vector(0)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Pods with 5 or more restarts in the last 5 mins", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "links": [ + { + "targetBlank": true, + "title": "", + "url": "d/f1b8caea-b0f2-4840-ad19-deeca4e1af98/aio-service-mq-unsubscribe?orgId=1" + } + ], + "mappings": [], + "max": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "#EAB839", + "value": 0.8 + }, + { + "color": "blue", + "value": 0.98 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 23 + }, + "id": 174, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "/^Value$/", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_unsubscribe_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "format": "table", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Last unsubscribe health [%]", + "transformations": [], + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 98, + "panels": [], + "title": "Current traffic (includes selftest traffic)", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "links": [ + { + "targetBlank": true, + "title": "", + "url": "d/f4606347-5cfb-47ce-adf5-06f7810a9863/aio-service-mq-current-traffic-includes-selftest-traffic?orgId=1" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 27 + }, + "id": 156, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_mq_publishes_received{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Inbound messages / s", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "links": [ + { + "targetBlank": true, + "title": "", + "url": "d/f4606347-5cfb-47ce-adf5-06f7810a9863/aio-service-mq-current-traffic-includes-selftest-traffic?orgId=1" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "subscription(s)" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 27 + }, + "id": 162, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(aio_mq_total_subscriptions{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Topic Subscriptions", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "links": [ + { + "targetBlank": true, + "title": "", + "url": "d/f4606347-5cfb-47ce-adf5-06f7810a9863/aio-service-mq-current-traffic-includes-selftest-traffic?orgId=1" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "msg/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 30 + }, + "id": 158, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_mq_publishes_sent{pod_type=\"FE\", cluster=~\"$cluster\", instance=~\"$namespace\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Outbound messages / s", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "links": [ + { + "targetBlank": true, + "title": "", + "url": "d/f4606347-5cfb-47ce-adf5-06f7810a9863/aio-service-mq-current-traffic-includes-selftest-traffic?orgId=1" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "session(s)" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 30 + }, + "id": 160, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(aio_mq_connected_sessions{hostname=~\".*frontend.*\", cluster=~\"$cluster\", instance=~\"$namespace\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Connected Sessions", + "type": "stat" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_node_status_condition", + "description": "PAS Cluster to view", + "hide": 0, + "includeAll": false, + "label": "Cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "kube_node_status_condition", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*cluster=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "hide": 0, + "includeAll": true, + "multi": true, + "name": "namespace", + "options": [], + "query": { + "query": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "aio-service-mq-main", + "uid": "b30870bc-d019-4d23-9e8e-6a2cf64a7907", + "version": 33, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-service-mq-ping-1698853769308.json b/samples/dashboard/grafana-dashboards/aio-service-mq-ping-1698853769308.json new file mode 100644 index 0000000..5b557d4 --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-service-mq-ping-1698853769308.json @@ -0,0 +1,899 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 2, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Ping health represents the health of the E4K broker. It is calculated as an average value of ping operation status for each attempt.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 28, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 1, + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "orange", + "value": 80 + }, + { + "color": "blue", + "value": 98 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 13, + "x": 0, + "y": 0 + }, + "id": 17, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "avg(aio_mq_ping_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"})", + "format": "table", + "legendFormat": "Health", + "range": true, + "refId": "A" + } + ], + "title": "Ping Health [%] (Avg)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "mode": "basic", + "type": "color-background" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Value (last)" + }, + "properties": [ + { + "id": "custom.width", + "value": 92 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "route" + }, + "properties": [ + { + "id": "custom.width", + "value": 911 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value (mean)" + }, + "properties": [ + { + "id": "custom.width", + "value": 109 + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 13, + "x": 0, + "y": 8 + }, + "id": 18, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_ping_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "format": "table", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Ping Health [%] (Avg) per route", + "transformations": [ + { + "id": "groupBy", + "options": { + "fields": { + "Value": { + "aggregations": [ + "last", + "mean" + ], + "operation": "aggregate" + }, + "route": { + "aggregations": [], + "operation": "groupby" + } + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 28, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 15 + }, + "id": 19, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_ping_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "legendFormat": "Mean", + "range": true, + "refId": "A" + } + ], + "title": "Avg ping latency [ms] (99th pctl)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 28, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 7, + "x": 6, + "y": 15 + }, + "id": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_ping_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "legendFormat": "Standard deviation", + "range": true, + "refId": "A" + } + ], + "title": "Std dev ping latency [ms] (99th pctl)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "1 Std Dev" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#ffb000", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "2 Std Dev" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#fe6100", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "LCL" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#dc267f", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "UCL" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#dc267f", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Last" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#e6e5ea", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 13, + "x": 0, + "y": 23 + }, + "id": 21, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_ping_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "legendFormat": "Mean", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_ping_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"} - aio_mq_ping_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "1 Std Dev", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_ping_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"} - 2*aio_mq_ping_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "2 Std Dev", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_ping_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"} - 3*aio_mq_ping_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "LCL", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_ping_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"} + aio_mq_ping_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "1 Std Dev", + "range": true, + "refId": "E" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_ping_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"} + 2*aio_mq_ping_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "2 Std Dev", + "range": true, + "refId": "F" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_ping_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"} + 3*aio_mq_ping_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "UCL", + "range": true, + "refId": "G" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_ping_latency_last_value_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "Last", + "range": true, + "refId": "H" + } + ], + "title": "Avg ping latency [ms] (99th pctl) Control Chart", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-BlYlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 13, + "x": 0, + "y": 33 + }, + "id": 22, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_ping_latency_route_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Ping latency per route [ms]", + "type": "timeseries" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_node_status_condition", + "description": "PAS Cluster to view", + "hide": 0, + "includeAll": false, + "label": "Cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "kube_node_status_condition", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*cluster=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "hide": 0, + "includeAll": true, + "multi": true, + "name": "namespace", + "options": [], + "query": { + "query": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "aio-service-mq-ping", + "uid": "c58ee063-e5f3-4829-ae8f-0160127759cc", + "version": 6, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-service-mq-publish-1698853774663.json b/samples/dashboard/grafana-dashboards/aio-service-mq-publish-1698853774663.json new file mode 100644 index 0000000..19dae9f --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-service-mq-publish-1698853774663.json @@ -0,0 +1,1044 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 2, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Publish health represents the health of the E4K broker. It is calculated as an average value of replication correctness for each route", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds", + "seriesBy": "last" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 28, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "max": 1, + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "orange", + "value": 80 + }, + { + "color": "blue", + "value": 98 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 13, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "columns": [ + { + "selector": "Correctness", + "text": "Health", + "type": "number" + }, + { + "selector": "Time", + "text": "Time", + "type": "timestamp" + } + ], + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "avg(aio_mq_publish_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"})", + "filters": [], + "format": "table", + "global_query_id": "", + "legendFormat": "Health", + "range": true, + "refId": "A", + "root_selector": "" + } + ], + "title": "Publish Health [%] (Avg)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "mode": "basic", + "type": "color-background" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "route" + }, + "properties": [ + { + "id": "custom.width", + "value": 913 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value (mean)" + }, + "properties": [ + { + "id": "custom.width", + "value": 109 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value (last)" + }, + "properties": [ + { + "id": "custom.width", + "value": 92 + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 13, + "x": 0, + "y": 9 + }, + "id": 10, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "columns": [], + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "aio_mq_publish_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "filters": [], + "format": "table", + "global_query_id": "", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "root_selector": "" + } + ], + "title": "Publish Health [%] (Avg) per route", + "transformations": [ + { + "id": "groupBy", + "options": { + "fields": { + "Value": { + "aggregations": [ + "last", + "mean" + ], + "operation": "aggregate" + }, + "route": { + "aggregations": [], + "operation": "groupby" + } + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 28, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 15 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "columns": [ + { + "selector": "Time", + "text": "Time", + "type": "timestamp" + }, + { + "selector": "Mu", + "text": "Publish Latency Average", + "type": "number" + } + ], + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_publish_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "filters": [], + "format": "timeseries", + "global_query_id": "", + "legendFormat": "Mean", + "parser": "simple", + "range": true, + "refId": "A", + "root_selector": "" + } + ], + "title": "Avg publish latency [ms] (99th pctl)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 28, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "Standard deviation" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 7, + "x": 6, + "y": 15 + }, + "id": 14, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "columns": [ + { + "selector": "Time", + "text": "Time", + "type": "timestamp" + }, + { + "selector": "Sigma", + "text": "Publish Latency Variance", + "type": "number" + } + ], + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_publish_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "filters": [], + "format": "timeseries", + "global_query_id": "", + "legendFormat": "Standard deviation", + "range": true, + "refId": "A", + "root_selector": "" + } + ], + "title": "Std dev publish latency [ms] (99th pctl)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "#648FFF", + "mode": "fixed" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#648fff", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "1 Std Dev" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB000", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "2 Std Dev" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FE6100", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "LCL" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#DC267F", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "UCL" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#DC267F", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Last" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#e6e5ea", + "mode": "fixed" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 11, + "w": 13, + "x": 0, + "y": 23 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.1.7", + "targets": [ + { + "columns": [ + { + "selector": "Time", + "text": "Time", + "type": "timestamp" + }, + { + "selector": "Mu", + "text": "Avg Publish Latency", + "type": "number" + }, + { + "selector": "Min1Sigma", + "text": "Minus 1 Sigma", + "type": "number" + }, + { + "selector": "Min2Sigma", + "text": "Minus 2 Sigma", + "type": "number" + }, + { + "selector": "LCL", + "text": "LCL", + "type": "number" + }, + { + "selector": "Plus1Sigma", + "text": "Plus 1 Sigma", + "type": "number" + }, + { + "selector": "Plus2Sigma", + "text": "Plus 2 Sigma", + "type": "number" + }, + { + "selector": "UCL", + "text": "UCL", + "type": "number" + }, + { + "selector": "LastReading", + "text": "Last reading", + "type": "number" + } + ], + "computed_columns": [], + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_publish_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "filters": [], + "format": "timeseries", + "global_query_id": "", + "legendFormat": "Mean", + "parser": "simple", + "range": true, + "refId": "A", + "root_selector": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_publish_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"} - aio_mq_publish_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "1 Std Dev", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_publish_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"} - 2*aio_mq_publish_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "2 Std Dev", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_publish_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"} - 3*aio_mq_publish_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "LCL", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_publish_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"} + aio_mq_publish_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "1 Std Dev", + "range": true, + "refId": "E" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_publish_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"} + 2*aio_mq_publish_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "2 Std Dev", + "range": true, + "refId": "F" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_publish_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"} + 3*aio_mq_publish_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "UCL", + "range": true, + "refId": "G" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_publish_latency_last_value_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "Last", + "range": true, + "refId": "H" + } + ], + "title": "Avg publish latency [ms] (99th pctl) Control Chart", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "#648FFF", + "mode": "continuous-BlYlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue" + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 13, + "x": 0, + "y": 34 + }, + "id": 18, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_publish_latency_route_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "{{route}}", + "range": true, + "refId": "B" + } + ], + "title": "Publish message latency per route [ms]", + "type": "timeseries" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_node_status_condition", + "description": "PAS Cluster to view", + "hide": 0, + "includeAll": false, + "label": "Cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "kube_node_status_condition", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*cluster=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "hide": 0, + "includeAll": true, + "multi": true, + "name": "namespace", + "options": [], + "query": { + "query": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "aio-service-mq-publish", + "uid": "bf5237d2-7deb-4144-aa46-41e1c1629b30", + "version": 6, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-service-mq-state-store-1698853779699.json b/samples/dashboard/grafana-dashboards/aio-service-mq-state-store-1698853779699.json new file mode 100644 index 0000000..74b3ab7 --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-service-mq-state-store-1698853779699.json @@ -0,0 +1,411 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 2, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 99, + "panels": [], + "title": "State Store", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "insertions/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 1 + }, + "id": 157, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_mq_state_store_insertions{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])) / count(kube_pod_info{pod=~\"aio-mq-dmqtt-backend.*0\",cluster=~\"$cluster\", namespace=~\"$namespace\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Key Insertions / s", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "modifications/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 1 + }, + "id": 162, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_mq_state_store_modifications{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])) / count(kube_pod_info{pod=~\"aio-mq-dmqtt-backend.*0\",cluster=~\"$cluster\", namespace=~\"$namespace\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Key modifications / s", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "retrievals/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 4 + }, + "id": 158, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_mq_state_store_retrievals{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])) / count(kube_pod_info{pod=~\"aio-mq-dmqtt-backend.*0\",cluster=~\"$cluster\", namespace=~\"$namespace\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Retrievals / s", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "deletions/s" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 4 + }, + "id": 160, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_mq_state_store_deletions{cluster=~\"$cluster\", namespace=~\"$namespace\"}[$__rate_interval])) / count(kube_pod_info{pod=~\"aio-mq-dmqtt-backend.*0\",cluster=~\"$cluster\", namespace=~\"$namespace\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Deletions / s", + "type": "stat" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_node_status_condition", + "description": "PAS Cluster to view", + "hide": 0, + "includeAll": false, + "label": "Cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "kube_node_status_condition", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*cluster=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "hide": 0, + "includeAll": true, + "multi": true, + "name": "namespace", + "options": [], + "query": { + "query": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "aio-service-mq-state-store", + "uid": "bdb9dfbd-ee0b-4666-8bbc-29eea7fe87ef", + "version": 9, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-service-mq-subscribe-1698853784238.json b/samples/dashboard/grafana-dashboards/aio-service-mq-subscribe-1698853784238.json new file mode 100644 index 0000000..bbc2ac2 --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-service-mq-subscribe-1698853784238.json @@ -0,0 +1,1018 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 2, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Publish health represents the health of the E4K broker. It is calculated as an average value of replication correctness for each route", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds", + "seriesBy": "last" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 28, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "max": 1, + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "orange", + "value": 80 + }, + { + "color": "blue", + "value": 98 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 13, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "columns": [ + { + "selector": "Correctness", + "text": "Health", + "type": "number" + }, + { + "selector": "Time", + "text": "Time", + "type": "timestamp" + } + ], + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "avg(aio_mq_subscribe_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"})", + "filters": [], + "format": "table", + "global_query_id": "", + "legendFormat": "Health", + "range": true, + "refId": "A", + "root_selector": "" + } + ], + "title": "Subscribe Health [%] (Avg)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "mode": "basic", + "type": "color-background" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "route" + }, + "properties": [ + { + "id": "custom.width", + "value": 902 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value (mean)" + }, + "properties": [ + { + "id": "custom.width", + "value": 109 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value (last)" + }, + "properties": [ + { + "id": "custom.width", + "value": 101 + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 13, + "x": 0, + "y": 9 + }, + "id": 10, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "columns": [], + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "aio_mq_subscribe_route_replication_correctness{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "filters": [], + "format": "table", + "global_query_id": "", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "root_selector": "" + } + ], + "title": "Subscribe Health [%] (Avg) per route", + "transformations": [ + { + "id": "groupBy", + "options": { + "fields": { + "Value": { + "aggregations": [ + "last", + "mean" + ], + "operation": "aggregate" + }, + "route": { + "aggregations": [], + "operation": "groupby" + } + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 28, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 15 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "columns": [ + { + "selector": "Time", + "text": "Time", + "type": "timestamp" + }, + { + "selector": "Mu", + "text": "Publish Latency Average", + "type": "number" + } + ], + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_subscribe_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "filters": [], + "format": "timeseries", + "global_query_id": "", + "legendFormat": "Mean", + "parser": "simple", + "range": true, + "refId": "A", + "root_selector": "" + } + ], + "title": "Avg subscribe latency [ms] (99th pctl)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 28, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 7, + "x": 6, + "y": 15 + }, + "id": 14, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "columns": [ + { + "selector": "Time", + "text": "Time", + "type": "timestamp" + }, + { + "selector": "Sigma", + "text": "Publish Latency Variance", + "type": "number" + } + ], + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_subscribe_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "filters": [], + "format": "timeseries", + "global_query_id": "", + "legendFormat": "Standard deviation", + "range": true, + "refId": "A", + "root_selector": "" + } + ], + "title": "Std dev subscribe latency [ms] (99th pctl)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "#648FFF", + "mode": "fixed" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#648fff", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "1 Std Dev" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFB000", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "2 Std Dev" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FE6100", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "LCL" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#DC267F", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "UCL" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#DC267F", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Last" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#e6e5ea", + "mode": "fixed" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 11, + "w": 13, + "x": 0, + "y": 23 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.1.7", + "targets": [ + { + "columns": [ + { + "selector": "Time", + "text": "Time", + "type": "timestamp" + }, + { + "selector": "Mu", + "text": "Avg Publish Latency", + "type": "number" + }, + { + "selector": "Min1Sigma", + "text": "Minus 1 Sigma", + "type": "number" + }, + { + "selector": "Min2Sigma", + "text": "Minus 2 Sigma", + "type": "number" + }, + { + "selector": "LCL", + "text": "LCL", + "type": "number" + }, + { + "selector": "Plus1Sigma", + "text": "Plus 1 Sigma", + "type": "number" + }, + { + "selector": "Plus2Sigma", + "text": "Plus 2 Sigma", + "type": "number" + }, + { + "selector": "UCL", + "text": "UCL", + "type": "number" + }, + { + "selector": "LastReading", + "text": "Last reading", + "type": "number" + } + ], + "computed_columns": [], + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_subscribe_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "filters": [], + "format": "timeseries", + "global_query_id": "", + "legendFormat": "Mean", + "parser": "simple", + "range": true, + "refId": "A", + "root_selector": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_subscribe_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"} - aio_mq_subscribe_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "1 Std Dev", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_subscribe_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"} - 2*aio_mq_subscribe_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "2 Std Dev", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_subscribe_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"} - 3*aio_mq_subscribe_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "LCL", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_subscribe_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"} + aio_mq_subscribe_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "1 Std Dev", + "range": true, + "refId": "E" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_subscribe_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"} + 2*aio_mq_subscribe_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "2 Std Dev", + "range": true, + "refId": "F" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_subscribe_latency_mu_ms{cluster=~\"$cluster\", instance=~\"$namespace\"} + 3*aio_mq_subscribe_latency_sigma_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "UCL", + "range": true, + "refId": "G" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_subscribe_latency_last_value_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "Last", + "range": true, + "refId": "H" + } + ], + "title": "Avg subscribe latency [ms] (99th pctl) Control Chart", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "#648FFF", + "mode": "continuous-BlYlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue" + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 13, + "x": 0, + "y": 34 + }, + "id": 18, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "aio_mq_subscribe_latency_route_ms{cluster=~\"$cluster\", instance=~\"$namespace\"}", + "hide": false, + "legendFormat": "{{route}}", + "range": true, + "refId": "B" + } + ], + "title": "Subscribe latency per route [ms]", + "type": "timeseries" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_node_status_condition", + "description": "PAS Cluster to view", + "hide": 0, + "includeAll": false, + "label": "Cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "kube_node_status_condition", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*cluster=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "hide": 0, + "includeAll": true, + "multi": true, + "name": "namespace", + "options": [], + "query": { + "query": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "aio-service-mq-subscribe", + "uid": "b5d606dc-a841-4ec0-b7c5-4f1d37c4e877", + "version": 6, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/aio-service-opcua-1698853789067.json b/samples/dashboard/grafana-dashboards/aio-service-opcua-1698853789067.json new file mode 100644 index 0000000..2101060 --- /dev/null +++ b/samples/dashboard/grafana-dashboards/aio-service-opcua-1698853789067.json @@ -0,0 +1,1893 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + }, + { + "name": "DS_AZURE_MONITOR", + "label": "Azure Monitor", + "description": "", + "type": "datasource", + "pluginId": "grafana-azure-monitor-datasource", + "pluginName": "Azure Monitor" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "grafana-azure-monitor-datasource", + "name": "Azure Monitor", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "logs", + "name": "Logs", + "version": "" + }, + { + "type": "panel", + "id": "piechart", + "name": "Pie chart", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 12, + "panels": [], + "title": "System", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum by(pod) (rate(container_cpu_usage_seconds_total{pod=~\"aio-opc.*|.*opc-ua-connector.*\", cluster=\"$cluster\", container=\"\", image=\"\"}[$__rate_interval])) * 1000", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Pods CPU Utilization [Millicores]", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "mbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum by (pod) (container_memory_working_set_bytes{pod=~\"aio-opc.*|.*opc-ua-connector.*\", cluster=\"$cluster\", container=\"\", image=\"\"} / (1024*1024))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Pods Memory Utilization [MiB]", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 6, + "panels": [], + "title": "Supervisor", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "#EAB839", + "value": 95 + }, + { + "color": "green", + "value": 100 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 10 + }, + "id": 37, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "(sum(rate(aio_opc_mqtt_message_publishing_duration_count{service_name=\"supervisor\", aio_opc_mqtt_publish_result=\"Success\", cluster=\"$cluster\"}[$__rate_interval])) * 100) / sum(rate(aio_opc_mqtt_message_publishing_duration_count{service_name=\"supervisor\", cluster=\"$cluster\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "MQTT Publish Success Rate", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 4, + "y": 10 + }, + "id": 8, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "exemplar": false, + "expr": "sum(aio_opc_endpoint_count{cluster=\"$cluster\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Configured Endpoints", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 8, + "y": 10 + }, + "id": 4, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "sum by(service_name) (process_runtime_dotnet_thread_pool_threads_count{exported_job=~\"^.*/supervisor$\", cluster=\"$cluster\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Thread Pool Thread Count", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 10 + }, + "id": 18, + "options": { + "dedupStrategy": "none", + "enableLogDetails": true, + "prettifyLogMessage": false, + "showCommonLabels": false, + "showLabels": false, + "showTime": false, + "sortOrder": "Descending", + "wrapLogMessage": false + }, + "pluginVersion": "9.5.8", + "targets": [ + { + "azureLogAnalytics": { + "query": "ContainerLogV2\r\n| where TimeGenerated >= $__timeFrom() and TimeGenerated <= $__timeTo()\r\n| where _ResourceId contains '$cluster'\r\n| where ContainerName == 'aio-opc-supervisor'\r\n| where LogSource == 'stdout'\r\n| where LogMessage startswith '<4>'\r\n| order by TimeGenerated desc\r\n| project TimeGenerated, LogMessage, ContainerName, PodName", + "resources": [ + "/subscriptions/af342bf1-1ace-41df-902c-47921400551b" + ] + }, + "azureMonitor": { + "allowedTimeGrainsMs": [], + "timeGrain": "auto" + }, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "queryType": "Azure Log Analytics", + "refId": "A" + } + ], + "title": "Errors and Warnings", + "type": "logs" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 14 + }, + "id": 41, + "options": { + "legend": { + "displayMode": "list", + "placement": "right", + "showLegend": true, + "values": [ + "percent" + ] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "sum" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "rate(aio_opc_mqtt_message_publishing_duration_count{service_name=\"supervisor\", cluster=\"$cluster\"}[$__rate_interval])", + "legendFormat": "{{aio_opc_mqtt_publish_result}}", + "range": true, + "refId": "A" + } + ], + "title": "MQTT Publish Result Code Distribution", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 4, + "y": 14 + }, + "id": 2, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "sum(aio_opc_asset_count{cluster=\"$cluster\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Number of Assets", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + }, + { + "color": "#EAB839", + "value": 3 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 8, + "y": 14 + }, + "id": 47, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "sum by(job) (process_runtime_dotnet_thread_pool_queue_length{service_name=~\"supervisor\", cluster=\"$cluster\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Thread Pool Queue Length", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 18 + }, + "id": 35, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "histogram_quantile(0.95, sum by(le) (rate(aio_opc_mqtt_message_publishing_duration_bucket{service_name=~\"supervisor\", cluster=\"$cluster\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "MQTT Publishing Latency P95 [ms]", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 22 + }, + "id": 44, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "histogram_quantile(0.99, sum by(le) (rate(aio_opc_mqtt_message_publishing_duration_bucket{service_name=~\"supervisor\", cluster=\"$cluster\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "MQTT Publishing Latency P99 [ms]", + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 24, + "panels": [], + "repeat": "application", + "repeatDirection": "h", + "title": "OPC UA Connector", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "#EAB839", + "value": 95 + }, + { + "color": "green", + "value": 100 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 27 + }, + "id": 36, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_opc_mqtt_message_publishing_duration_count{service_name=\"connector-sidecar\", aio_opc_mqtt_publish_result=\"Success\", cluster=\"$cluster\"}[$__rate_interval])) / sum(rate(aio_opc_mqtt_message_publishing_duration_count{service_name=\"connector-sidecar\", cluster=\"$cluster\"}[$__rate_interval])) * 100", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "MQTT Publish Success Rate", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 4, + "y": 27 + }, + "id": 46, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_opc_asset_telemetry_data_change_count{cluster=\"$cluster\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Data Changes per Second", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 8, + "y": 27 + }, + "id": 32, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "sum by(aio_opc_module_name) (process_runtime_dotnet_thread_pool_threads_count{service_name=\"opcua-connector\", cluster=\"$cluster\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Connector Thread Pool Thread Count", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 27 + }, + "id": 26, + "options": { + "dedupStrategy": "none", + "enableLogDetails": true, + "prettifyLogMessage": false, + "showCommonLabels": false, + "showLabels": false, + "showTime": false, + "sortOrder": "Descending", + "wrapLogMessage": false + }, + "pluginVersion": "9.5.8", + "targets": [ + { + "azureLogAnalytics": { + "query": "ContainerLogV2\r\n| where TimeGenerated >= $__timeFrom() and TimeGenerated <= $__timeTo()\r\n| where _ResourceId contains '$cluster'\r\n| where ContainerName matches regex '(^(opc-ua-).*|.*-opc-ua-.*)'\r\n| where LogSource == 'stdout'\r\n| where LogMessage startswith '<4>'\r\n| order by TimeGenerated desc\r\n| project TimeGenerated, LogMessage, PodName, ContainerName\r\n| take 100", + "resources": [ + "/subscriptions/af342bf1-1ace-41df-902c-47921400551b" + ] + }, + "azureMonitor": { + "allowedTimeGrainsMs": [], + "timeGrain": "auto" + }, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "queryType": "Azure Log Analytics", + "refId": "A" + } + ], + "title": "Errors and Warnings", + "type": "logs" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 31 + }, + "id": 40, + "options": { + "legend": { + "displayMode": "list", + "placement": "right", + "showLegend": true, + "values": [ + "percent" + ] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "sum" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "sum by(aio_opc_mqtt_publish_result) (rate(aio_opc_mqtt_message_publishing_duration_count{service_name=\"connector-sidecar\", cluster=\"$cluster\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "MQTT Publish Result Code Distribution", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 4, + "y": 31 + }, + "id": 50, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "sum(rate(aio_opc_asset_telemetry_value_change_count{cluster=\"$cluster\"}[$__rate_interval]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Value Changes per Second", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 8, + "y": 31 + }, + "id": 48, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "sum by(aio_opc_module_name) (process_runtime_dotnet_thread_pool_queue_length{service_name=\"opcua-connector\", cluster=\"$cluster\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Connector Thread Pool Queue Length", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 35 + }, + "id": 34, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "histogram_quantile(0.95, sum by(le) (rate(aio_opc_mqtt_message_publishing_duration_bucket{service_name=~\"connector-sidecar\", cluster=\"$cluster\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "MQTT Publishing Latency P95 [ms]", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 4, + "y": 35 + }, + "id": 51, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "histogram_quantile(0.95, sum by(le) (rate(aio_opc_data_change_processing_duration_bucket{cluster=\"$cluster\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Data Change Processing Latency P95 [ms]", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 8, + "y": 35 + }, + "id": 45, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "sum by(aio_opc_module_name) (process_runtime_dotnet_thread_pool_threads_count{service_name=\"connector-sidecar\", cluster=\"$cluster\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Sidecar Thread Pool Count", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue" + }, + { + "color": "yellow", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 12, + "y": 35 + }, + "id": 42, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "aio_opc_asset_telemetry_value_change_count{cluster=\"$cluster\", aio_opc_value_change_status=\"localoverride\"}", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Server Queue Overflow Rate", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 39 + }, + "id": 43, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "histogram_quantile(0.99, sum by(le) (rate(aio_opc_mqtt_message_publishing_duration_bucket{service_name=~\"connector-sidecar\", cluster=\"$cluster\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "MQTT Publishing Latency P99 [ms]", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 4, + "y": 39 + }, + "id": 52, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, sum by(le) (rate(aio_opc_event_processing_duration_bucket{cluster=\"$cluster\"}[$__rate_interval])))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Event Processing Latency P95 [ms]", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 8, + "y": 39 + }, + "id": 49, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "sum by(aio_opc_module_name) (process_runtime_dotnet_thread_pool_queue_length{service_name=\"connector-sidecar\", cluster=\"$cluster\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Sidecar Thread Pool Queue Length", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 28, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue" + }, + { + "color": "yellow", + "value": 20 + }, + { + "color": "red", + "value": 40 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "{__name__=\"aio_opc_output_queue_count\", application=\"az-e4i-opcua-connector\", exported_job=\"az-e4i-opcua-connector/opc-ua-connector\", instance=\"otel-collector.monitoring.svc.cluster.local:8889\", job=\"otel\", module_name=\"opc-ua-connector\", module_type=\"opc-ua-connector\", service_name=\"opc-ua-connector\", service_namespace=\"az-e4i-opcua-connector\", service_version=\"1.2.3\", telemetry_sdk_language=\"dotnet\", telemetry_sdk_name=\"opentelemetry\", telemetry_sdk_version=\"1.5.1\"}" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 12, + "y": 39 + }, + "id": 30, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.5.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "expr": "sum by(aio_opc_module_name) (aio_opc_output_queue_count{cluster=\"$cluster\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Output Queue Size", + "type": "timeseries" + } + ], + "refresh": "1m", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "label_values(up{job=\"kube-state-metrics\"}, cluster)", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "label_values(up{job=\"kube-state-metrics\"}, cluster)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "aio-service-opcua", + "uid": "eaee1655-8c82-4b00-9258-5fa05ba16f04", + "version": 15, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/health-service-akri-1698853793929.json b/samples/dashboard/grafana-dashboards/health-service-akri-1698853793929.json new file mode 100644 index 0000000..ab9398e --- /dev/null +++ b/samples/dashboard/grafana-dashboards/health-service-akri-1698853793929.json @@ -0,0 +1,3910 @@ +{ + "__inputs": [ + { + "name": "DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST", + "label": "Managed_Prometheus_jajens-azmonworkspace-test", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + }, + { + "name": "DS_AZURE_MONITOR", + "label": "Azure Monitor", + "description": "", + "type": "datasource", + "pluginId": "grafana-azure-monitor-datasource", + "pluginName": "Azure Monitor" + }, + { + "name": "VAR_COMPONENT", + "type": "constant", + "label": "component", + "value": "^(aio-akri-|akri-).*", + "description": "" + }, + { + "name": "VAR_COMPONENT_TEXT", + "type": "constant", + "label": "component_text", + "value": "AKRI", + "description": "" + }, + { + "name": "VAR_MYPREFIX_LATENCY_THRESHOLD_MS", + "type": "constant", + "label": "myprefix_latency_threshold_ms", + "value": "5000", + "description": "" + }, + { + "name": "VAR_LATENCY_PERCENTILE", + "type": "constant", + "label": "latency_percentile", + "value": "0.95", + "description": "" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.13" + }, + { + "type": "datasource", + "id": "grafana-azure-monitor-datasource", + "name": "Azure Monitor", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "piechart", + "name": "Pie chart", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "state-timeline", + "name": "State timeline", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 8, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n Azure Edge Services - ${component_text} Health\n
\n
\n   Scenario Health (SLO/RUM) related to ${component_text}\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 10, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Service Health (Synthetics/Self-test)\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 60, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for ${component_text} ${__field.labels._}", + "url": "${__field.labels.url}?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#7f7f7f", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + }, + { + "color": "#7f7f7f", + "value": 404 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "^Self-test.*[^)]$" + }, + "properties": [ + { + "id": "links" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".* Overall Health$" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 1 + }, + { + "id": "links" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 5 + }, + "id": 16, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.72, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(min(\r\n label_replace(#label_replace(\r\n (min(\r\n aio_akri_instance_count{cluster=~\"$cluster\"} or\r\n vector(0)>0\r\n ) or vector(404))\r\n ,\"_\",\"Akri Instance Count\",\"\",\"\") or\r\n vector(0)>0\r\n),\"_\",\"$component_text Overall Health\",\"\",\"\")", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#label_replace(min(\r\n label_replace( \r\n #TODO: REPLACE BELOW WITH ALL OF THE INDIVIDUAL HEALTH-TEST SIGNALS THAT MAKE UP OVERALL SIGNAL, THEN COPY AND PASTE INTO QUERY A\r\n (min(\r\n 1 * sgn(\r\n 100*sum(rate(e4i_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\",e4i_mqtt_publish_result=\"Success\"}[$__rate_interval]))\r\n / sum(rate(e4i_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\"}[$__rate_interval]))\r\n > 99) or\r\n 0 * sgn(sum(rate(e4i_mqtt_message_publishing_duration_count{cluster=\"$cluster\",service_name=\"supervisor\"}[$__rate_interval])) > 0) or\r\n vector(0)>0\r\n ) or vector(-1))\r\n #,\"url\",\"/d/f46e5384-d78d-480a-911c-0328cb20b224/e4k-ping\",\"\",\"\") # UPDATE AND ENABLE WITH LABEL_REPLACE TO HAVE INLINE DATA LINK\r\n ,\"_\",\"Self-test Success Rate\",\"\",\"\") or\r\n label_replace(\r\n (min(\r\n 1 * sgn(max(histogram_quantile(0.95, rate(\r\n e4i_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n ))) < $myprefix_latency_threshold_ms) or\r\n 0 * sgn(max(histogram_quantile(0.95, rate(\r\n e4i_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n ))) >= $myprefix_latency_threshold_ms) or\r\n vector(0)>0\r\n ) or vector(404))\r\n #,\"url\",\"/d/f5a5c523-2cb6-42d8-b23f-06b0227fe40b/e4k-connect\",\"\",\"\")# UPDATE AND ENABLE WITH LABEL_REPLACE TO HAVE INLINE DATA LINK\r\n ,\"_\",\"Self-test latency\",\"\",\"\") or \r\n vector(0)>0\r\n#),\"_\",\"$component_text Overall Health\",\"\",\"\")", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "B" + } + ], + "title": "Service Health - TODO UPDATE ME", + "transformations": [], + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "series", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Click for Bluefin details", + "url": "/d/e57b7777-71be-43a8-87bd-d917391b154f/bluefin-overview?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 0.8 + }, + { + "color": "dark-green", + "value": 1 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Supervisor errors" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "line" + }, + { + "id": "custom.lineWidth", + "value": 3 + }, + { + "id": "custom.fillOpacity", + "value": 5 + }, + { + "id": "custom.pointSize", + "value": 5 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 0, + 5 + ], + "fill": "dot" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisLabel", + "value": "Error counts" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Supervisor Success Rate" + }, + "properties": [ + { + "id": "custom.axisSoftMax" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "0": { + "color": "#808080", + "index": 0 + } + }, + "type": "value" + } + ] + }, + { + "id": "max", + "value": 101 + }, + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 5 + }, + "id": 28, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "asc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(# BELOW IS AN EXAMPLE; REPLACE WITH WHATEVER PROVIDES DETAILS BEHIND HEALTH SIGNAL\r\n 100*sum(rate(e4i_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\",e4i_mqtt_publish_result=\"Success\"}[$__rate_interval]))\r\n / sum(rate(e4i_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\"}[$__rate_interval]))\r\n ,\"_\",\"Supervisor Success Rate\",\"\",\"\") or\r\nlabel_replace(\r\n 60*sum(rate(e4i_mqtt_message_publishing_duration_count\r\n {cluster=\"$cluster\",service_name=\"supervisor\",e4i_mqtt_publish_result!=\"Success\"}[$__rate_interval]))\r\n# #0 * sgn(\r\n# round(sum(increase(stage_errors{cluster=~\"$cluster\",cloud_resource_id=~\"$bf_pipeline4selftest\"}[$__rate_interval])))#) or\r\n# #or vector(3)\r\n ,\"_\",\"Supervisor errors\",\"\",\"\") or\r\n vector(0)>0", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Self-test Output and Errors - TODO UPDATE ME", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Click for Bluefin details", + "url": "/d/e57b7777-71be-43a8-87bd-d917391b154f/bluefin-overview?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "hidden-timeline" + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Self-test latency threshold" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Self-test pipeline latency over threshold" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.lineWidth", + "value": 3 + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 9 + }, + "id": 29, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace( # BELOW IS AN EXAMPLE; REPLACE WITH WHATEVER PROVIDES DETAILS BEHIND HEALTH SIGNAL\r\n max(histogram_quantile(0.95, rate(\r\n e4i_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n ))) \r\n ,\"_\",\"Self-test pipeline latency\",\"\",\"\") or\r\nlabel_replace($myprefix_latency_threshold_ms * sgn(\r\n max(histogram_quantile(0.95, rate(\r\n e4i_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n )))\r\n ),\"_\",\"Self-test latency threshold\",\"\",\"\") or\r\nlabel_replace(label_replace(\r\n max(histogram_quantile(0.95, rate(\r\n e4i_mqtt_message_publishing_duration_bucket{cluster=\"$cluster\",service_name=~\"supervisor\"}[5m]\r\n ))) >= $myprefix_latency_threshold_ms\r\n ,\"x\",\"Over threshold\",\"\",\"\")\r\n ,\"_\",\"Self-test pipeline latency over threshold\",\"\",\"\") or\r\nlabel_replace(vector(0),\"_\",\"hidden-timeline\",\"\",\"\") or\r\nvector(0)>0", + "hide": false, + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + } + ], + "title": "Self-test Latency - TODO UPDATE ME", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 12, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Golden Metrics\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [ + { + "options": { + "match": "null+nan", + "result": { + "color": "transparent", + "index": 0 + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".*s$" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisLabel", + "value": "total count" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*[/]sec[)]$" + }, + "properties": [ + { + "id": "custom.axisLabel", + "value": "throughput (msgs/sec)" + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 15 + }, + "id": 50, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(rate(my_counter_metric_1{cluster=\"$cluster\"}[$__rate_interval]))\r\n ,\"_\",\"LABEL-1\",\"\",\"\") or\r\nlabel_replace(\r\n sum(my_gauge_metric_2{cluster=\"$cluster\"})\r\n ,\"_\",\"LABEL-2\",\"\",\"\") or\r\nlabel_replace(vector(1),\"_\",\"TODO: Usage/Volume\",\"\",\"\") or # Comment out or remove this line when done\r\nvector(0) > 0", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Usage/Volume - TODO UPDATE ME", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Success Rate" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 4 + }, + { + "id": "custom.axisSoftMin", + "value": 0 + }, + { + "id": "custom.axisSoftMax", + "value": 101 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*(Errors)$" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "unit", + "value": "none" + }, + { + "id": "custom.axisLabel", + "value": "Error Count" + }, + { + "id": "custom.drawStyle", + "value": "bars" + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "custom.axisSoftMin", + "value": 0 + }, + { + "id": "custom.axisSoftMax", + "value": 20 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 15 + }, + "id": 51, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n my_success_rate_metric_or_computation{cluster=\"$cluster\"}\r\n ,\"_\",\".Success Rate\",\"\",\"\") * 100 or\r\nlabel_replace(\r\n sum(rate(my_error_count{cluster=\"$cluster\"}[$__rate_interval])) #or vector(0)\r\n ,\"_\",\"MY-LABEL-PREFIX Errors\",\"\",\"\") or\r\nlabel_replace(vector(1),\"_\",\"TODO: Success Rate\",\"\",\"\") or\r\nvector(0) > 0", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Success Rate/Errors - TODO UPDATE ME", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "Self-test.*" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 0, + 10 + ], + "fill": "dot" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 15 + }, + "id": 52, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "max by (_)(\r\n label_replace(label_replace(label_replace(\r\n histogram_quantile($latency_percentile, sum(rate(\r\n my_latency_histogram_bucket{cluster=\"$cluster\"}[$latency_quantile_range]\r\n )) by (le))\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"MY-LABEL-PREFIX Latency $1\",\"pout\",\"(.*)\") or\r\n label_replace(label_replace(label_replace(\r\n histogram_quantile($latency_percentile, rate(\r\n my_latency_histogram_bucket{cluster=\"$cluster\"}[$latency_quantile_range]))\r\n ,\"pin\",\"${latency_percentile}\",\"\",\"\"),\"pout\",\"P${1}\",\"pin\",\"^0[.](.*)$\")\r\n ,\"_\",\"MY-LABEL-PREFIX Latency $1 (worst)\",\"pout\",\"(.*)\") or\r\n vector(0)>0) or\r\nlabel_replace(vector(1),\"_\",\"TODO: Latency\",\"\",\"\") or\r\nvector(0)>0", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(histogram_quantile(0.95, rate(pipeline_latency_bucket{cluster=~\"$cluster|int-virtual-02\",cloud_resource_id=~\".*self-test-bluefin-pipeline.*\"}[$__rate_interval])),\"_\",\"P95\",\"\",\"\") or\r\nvector(0)>0", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Latency - TODO UPDATE ME", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMax": 15, + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Backpressure Rejection %" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 3 + }, + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "# rejected by .*" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "bars" + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisLabel", + "value": "Packet Rejected Count" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 15 + }, + "id": 53, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n max(my_saturation_gauge_metric_1{cluster=~\"$cluster\"})\r\n ,\"_\",\"MY SATURATION LABEL\",\"\",\"\") or\r\nlabel_replace(vector(1),\"_\",\"TODO: Saturation\",\"\",\"\") or\r\nvector(0)>0", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Saturation - TODO UPDATE ME", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 11, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Infrastructure Workload Health\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": false + }, + "links": [ + { + "targetBlank": true, + "title": "Click for more details", + "url": "/d/eef9bf1c-b27a-4e86-a7f0-2a39cdfbeeca/health-infrastructure?${__all_variables}&${__url_time_range}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 25 + }, + "id": 31, + "links": [ + { + "targetBlank": true, + "title": "See infra workload health for all components", + "url": "/d/E5cCeHj4z/health-infra-workload?${cluster:queryparam}&${__url_time_range}" + } + ], + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 0.9, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Workload Readiness health\r\n############################\r\nlabel_replace(min(\r\navg(label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n label_replace(label_join(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n / label_replace(label_join(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n) by (workload) >=0 \r\n) or vector(0),\"_\",\"Workload Readiness\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Restart Health:\r\n############################\r\nlabel_replace(\r\n sgn(sum_over_time(sum(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[10m:1m]\r\n )*60)[1h:]) > 5) * 0.0 # RED: Cumulative restarts over X(5) time greater than Y(1h)\r\n or (max(rate(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[5m:1m]\r\n )*60*5) > 0) * 0.5 # YELLOW: restarts detected but below Red threshold\r\n or sgn(max(\r\n kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}\r\n + 1 >= 0))\r\n #or vector(1) # Healthy\r\n ,\"_\",\"Container Restart Health\",\"\",\"\")\r\n## uncomment below to t-shoot this health metric\r\n# or label_replace(sum_over_time(sum(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[10m:1m])*60)[1h:]),\"_\",\"Total-restarts-over-time\",\"\",\"\")\r\n# or label_replace((max(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\"}[5m:1m])*60*5) without (__name__,uid,instance,job) > 0),\"_\",\"restart\",\"\",\"\") # Base query for counting restarts\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container CPU top-level health\r\n################################\r\nlabel_replace(\r\nmin(sgn( # Check for throttling > N indicating container is exceeding its CPU limits\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m]) \r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m])\r\n >= 0.60) # If throttle create is greater than this percentage, we'll multiply sgn by 0.5 to show as error (or warning depending on threshold coloring)\r\n ) # by (namespace,container) # These are commented out for top-level\r\n * 0.0\r\nor\r\nmin(sgn( # Check for throttling > N indicating container is exceeding its CPU limits\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m]) \r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}[10m])\r\n >= 0.40) # If throttle create is greater than this percentage, we'll multiply sgn by 0.5 to show as error (or warning depending on threshold coloring)\r\n ) # by (namespace,container) # These are commented out for top-level\r\n * 0.5\r\nor\r\nmin( # Check to see if container is missing CPU Limits configuration\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"cpu\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n ) #by (namespace,container) # These are commented out for top-level\r\n,\"_\",\"Container CPU Health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "## Container Memory Health:\r\n###########################\r\nlabel_replace(\r\nmin( # Look for high memory utilization\r\n sgn((\r\n max(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container)\r\n / min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"memory\",pod=~\"${component:raw}\"}) by (namespace, container)\r\n ) >= .95) - 0.5 # show health state of 0.5 if container memory utilization >= 95%\r\n) #by (container) \r\nor\r\nmin( # Look for missing limits which we will show as 0 if missing\r\n sgn(min(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",resource=\"memory\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n or # if resource limit missing, we or to below to show namespace/container using CPU without limit as a zero to indicate red\r\n sgn(min(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",container!=\"\",pod=~\"${component:raw}\"}) by (namespace,container))\r\n # * 0 # TEMPORARILY DISABLING RED FOR MISSING LIMITS\r\n) #by (container) \r\n,\"_\",\"Container Memory health\",\"\",\"\")", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + } + ], + "title": "Health Summary", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "max(rate(container_cpu_usage_seconds_total{namespace=~\"alice-springs|symphony-k8s-system\",container=\"\",cpu=\"total\"}[5m])*300 > 0) ": "POD CPU (max)", + "min( # Workload ready percents (for deployment, daemonset, replicaset, and statefulset)\r\n label_replace(label_join(\r\n {job=\"kube-state-metrics\",namespace=~\"alice-springs|symphony-k8s-system\",\r\n __name__=~\"kube_(deployment|daemonset|replicaset|statefulset)_status_(replicas_ready|ready_replicas|number_ready)\"}\r\n ,\"workload\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n / label_replace(label_join(\r\n {job=\"kube-state-metrics\",namespace=~\"alice-springs|symphony-k8s-system\",\r\n __name__=~\"kube_(deployment|daemonset|replicaset|statefulset)_status_(replicas|desired_number_scheduled)\"}\r\n ,\"workload\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n) #by (workloadType) #namespace) #, workloadType) #, workload)": "Workload ready health" + } + } + } + ], + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 20 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 6, + "y": 25 + }, + "id": 33, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(sum ( # by(workloadType) (\r\n#min(\r\n# label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n label_replace(label_join(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n),\"_\",\"Ready\",\"\",\"\")\r\n# / label_replace(label_join(\r\n# kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\"$namespace\",daemonset=~\"${component:raw}\"} or\r\n# kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\"$namespace\",deployment=~\"${component:raw}\"} or\r\n# kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\"$namespace\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n# ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n#) by (workload) >=0 ", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "#min(\r\n# label_join( # Workload ready percents (for deployment, daemonset, and statefulset)\r\n# label_replace(label_join(\r\n# kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",deployment=~\"${component:raw}\"} or\r\n# kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",daemonset=~\"${component:raw}\"} or\r\n# kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\"$namespace\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"replicaset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_status_.*\")\r\n# / label_replace(label_join(\r\n label_replace(sum(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} or\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} or\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n# ,\"workloadName\", \"\", \"deployment\", \"daemonset\", \"statefulset\")\r\n# ,\"workloadType\", \"$1\", \"__name__\", \"kube_(.*)_(status|spec)_.*\")\r\n ),\"_\",\"Requested\",\"\",\"\")\r\n# ,\"workload\", \":\", \"workloadType\", \"workloadName\")\r\n#) by (workload) >=0 ", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Workloads", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 8, + "y": 25 + }, + "id": 35, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",daemonset=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor label_replace(vector(0),\"status\",\"Ready\",\"\",\"\")\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "DaemonSets", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 10, + "y": 25 + }, + "id": 37, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor label_replace(vector(0),\"status\",\"Ready\",\"\",\"\") # this is to zero if no workloads of this type exist\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "Deployments", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Not-Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ready" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 12, + "y": 25 + }, + "id": 39, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n sum(#sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n > 0)#)\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n sum(#sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",statefulset=~\"${component:raw}\"}\r\n )#)\r\n ,\"status\",\"Ready\",\"\",\"\")\r\nor \r\nlabel_replace(vector(0),\"status\",\"Ready\",\"\",\"\")\r\n# or label_replace(vector(1),\"status\",\"Not-Ready\",\"\",\"\") # UNCOMMENT THIS LINE TO TEST \"NOT-READY\" STATUS", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "label_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_spec_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_desired_number_scheduled{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"} \r\n - kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n > 0)),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Not-Ready\",\"\",\"\")\r\nor \r\nlabel_replace(\r\n label_replace(sum(sgn(\r\n kube_deployment_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"deployment\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_daemonset_status_number_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"daemonset\",\"\",\"\") or\r\n label_replace(sum(sgn(\r\n kube_statefulset_status_replicas_ready{cluster=~\"$cluster\",namespace=~\".*\",deployment=~\"${component:raw}\"}\r\n )),\"workload\",\"statefulset\",\"\",\"\")\r\n ,\"status\",\"Ready\",\"\",\"\")\r\n", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "C" + } + ], + "title": "StatefulSets", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 1 + }, + { + "color": "dark-orange", + "value": 5 + }, + { + "color": "red", + "value": 10 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 14, + "y": 25 + }, + "id": 41, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "max" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.13", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Container Restarts\r\nlabel_replace(ceil(sum_over_time(sum(rate(kube_pod_container_status_restarts_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\"}[10m:1m])*60)[1h:])),\"_\",\"restarts\",\"\",\"\")\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 40 + }, + { + "color": "red", + "value": 60 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percent containers with CPU Limits (%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "super-light-purple", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Usage (milli-cores)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisColorMode", + "value": "series" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Max Throttled (%)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "thresholds", + "seriesBy": "max" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 25 + }, + "id": 59, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\n(label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))*1000,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\") )\r\n# Percent of containers with limits defined\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"Percent containers with CPU Limits (%)\",\"\",\"\")\r\n# CPU Throttling:\r\nor label_replace(100*(max(\r\n rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n )),\"_\",\"CPU Max Throttled (%)\",\"\",\"\")\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(quantile_over_time(0.95,sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\nvector(0)>0\r\n# Sum of all limits defined, in Cores\r\nor label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# WIP:\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"WIP-PERCENT_WITH_LIMITS\",\"\",\"\")\r\nor label_replace(count(\r\n kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"})\r\n ,\"_\",\"WIP-NUMERATOR\",\"\",\"\")\r\nor label_replace(count(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) #without(cluster,container,cpu,id,image,instance,job,name,namespace,pod)\r\n ,\"_\",\"WIP-DENOMINATOR\",\"\",\"\")\r\n# ", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "CPU", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 80 + }, + { + "color": "orange", + "value": 85 + }, + { + "color": "red", + "value": 90 + }, + { + "color": "dark-red", + "value": 95 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Percent containers with Memory Limits (%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mem Working Bytes (MB)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "custom.axisColorMode", + "value": "series" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mem Max Usage vs Limit (%)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "thresholds", + "seriesBy": "max" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 25 + }, + "id": 61, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.4.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory Usage (MB version)\r\n(label_replace(sum(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"Mem Working Bytes (MB)\",\"\",\"\") )\r\n# Percent containers with limits\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"memory\"}) /\r\n count(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}) *100\r\n ,\"_\",\"Percent containers with Memory Limits (%)\",\"\",\"\")\r\n# Max Mem % Usage:\r\nor label_replace(100*(max(\r\n max_over_time((max by(container)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}))[10m:])\r\n / max by(container)(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"memory\"})\r\n )),\"_\",\"Mem Max Usage vs Limit (%)\",\"\",\"\")\r\n", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(quantile_over_time(0.95,sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\nvector(0)>0\r\n# Sum of all limits defined, in Cores\r\nor label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# WIP:\r\nor label_replace(\r\n count(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"}) /\r\n count(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) *100\r\n ,\"_\",\"WIP-PERCENT_WITH_LIMITS\",\"\",\"\")\r\nor label_replace(count(\r\n kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",resource=\"cpu\"})\r\n ,\"_\",\"WIP-NUMERATOR\",\"\",\"\")\r\nor label_replace(count(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\"$namespace4workloads\",pod=~\".*\",container!=\"\",cpu=\"total\"}) #without(cluster,container,cpu,id,image,instance,job,name,namespace,pod)\r\n ,\"_\",\"WIP-DENOMINATOR\",\"\",\"\")\r\n# ", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "milli-cores", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels._}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels._}.*" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Overall" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "number" + }, + "properties": [ + { + "id": "links" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 29 + }, + "id": 47, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(_)(\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum by(pod)(rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") or\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum (rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\".Overall\",\"\",\"\") or\r\nvector(0)>0)", + "legendFormat": "{{_}}", + "range": true, + "refId": "A" + } + ], + "title": "CPU Usage by Workload", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "working bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels._}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels._}.*" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byType", + "options": "number" + }, + "properties": [ + { + "id": "links" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 29 + }, + "id": 48, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(_)(\r\nlabel_replace(\r\n sum by(pod)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") \r\n)\r\n##(label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))*1000,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\") )\r\n## and label_replace(max_over_time(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))[3d:]) < 0.2,\"_\",\"CPU Usage (milli-cores)\",\"\",\"\")) # Show milli-cores if rate below 0.2 cores\r\n# CPU Time (cores version, if >= 0.2 cores)\r\n##or (label_replace(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval])),\"_\",\"CPU Usage (cores)\",\"\",\"\") \r\n## and label_replace(max_over_time(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))[3d:]) >= 0.2,\"_\",\"CPU Usage (cores)\",\"\",\"\")) # Show in cores if rate at or above 0.2 cores\r\n# Shows the max in millicores, used to determine which is shown (commented out for UX; only uncomment to debug above)\r\n#or label_replace(max_over_time(sum(rate(container_cpu_usage_seconds_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[$__rate_interval]))[3d:])*1000,\"_\",\"CPU Usage (milli-cores) MAX\",\"\",\"\")\r\n# Sum of all limits defined, in Cores\r\n##or label_replace(sum(kube_pod_container_resource_limits{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\",resource=\"cpu\"}),\"_\",\"CPU Limits (cores)\",\"\",\"\")\r\n# CPU Throttling:\r\n##or label_replace(100*(max(\r\n## rate(container_cpu_cfs_throttled_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n## / rate(container_cpu_cfs_periods_total{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"}[10m])\r\n## )),\"_\",\"CPU Max Throttled (%)\",\"\",\"\")\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Memory Usage by Workload", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Click on data series to drill down into pod details", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "milli-cores", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels.pod}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels.pod}" + } + ], + "mappings": [ + { + "options": { + "match": "null+nan", + "result": { + "color": "transparent", + "index": 0 + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ".Overall" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "custom.axisColorMode", + "value": "series" + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 37 + }, + "id": 56, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(pod)(\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum by(pod)(rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\"$1\",\"pod\",\"(.*)\") or #,\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") or\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum (rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"pod\",\".Overall\",\"\",\"\") or\r\nvector(0)>0)", + "hide": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# CPU Time (milli-cores version, if < 0.2 cores)\r\nmax by(_)(\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum by(pod)(rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") or\r\n label_replace(#quantile_over_time($latency_percentile,(\r\n sum (rate(\r\n container_cpu_usage_seconds_total{cluster=~\"$cluster\",pod=~\"${component:raw}\",container!=\"\"}\r\n [$__rate_interval]))#)[$latency_quantile_range:])\r\n *1000,\"_\",\".Overall\",\"\",\"\") or\r\nvector(0)>0)", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "CPU Usage by Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "Click on data series to drill down into pod details", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "working bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [ + { + "targetBlank": true, + "title": "Show details for [${__field.labels.pod}]", + "url": "/d/wlCiLDq4k/health-infra-pod?${__all_variables}&${__url_time_range}&var-pod=${__field.labels.pod}" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decmbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 37 + }, + "id": 57, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory working bytes\r\nmax by(pod)(\r\nlabel_replace(\r\n sum by(pod)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") \r\n)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "expr": "# Memory working bytes\r\nmax by(_)(\r\nlabel_replace(\r\n sum by(pod)(container_memory_working_set_bytes{cluster=~\"$cluster\",namespace=~\".*\",pod=~\"${component:raw}\",container!=\"\"})/(1024*1024),\"_\",\"$1\",\"pod\",\"(.*)(-[0-9]$|-[0-9]$|-[^-]+-.....$)\") \r\n)", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Memory Usage by Pod", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 45 + }, + "id": 13, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   Errors & Logs\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "yellow", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PodName" + }, + "properties": [ + { + "id": "custom.width", + "value": 300 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Reason" + }, + "properties": [ + { + "id": "custom.width", + "value": 112 + }, + { + "id": "custom.align", + "value": "center" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "Failed": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ] + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Count" + }, + "properties": [ + { + "id": "custom.width", + "value": 114 + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "color", + "value": { + "mode": "continuous-BlPu" + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.width", + "value": 200 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Message" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 55, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "LastSeen" + } + ] + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "azureLogAnalytics": { + "query": "KubeEvents\r\n//| where TimeGenerated > ago(1d)\r\n| where ClusterName == '$cluster'\r\n| where Name matches regex '${component:raw}'\r\n//| order by TimeGenerated desc\r\n| order by LastSeen desc, FirstSeen desc, TimeGenerated desc\r\n| project-rename PodName = Name\r\n| project FirstSeen, LastSeen, Count, PodName, Reason, Message\r\n| take 10", + "resources": [ + "/subscriptions/af342bf1-1ace-41df-902c-47921400551b" + ], + "resultFormat": "table" + }, + "azureMonitor": { + "allowedTimeGrainsMs": [], + "timeGrain": "auto" + }, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "queryType": "Azure Log Analytics", + "refId": "A" + } + ], + "title": "Last 10 Kube Events entries (from $cluster)", + "type": "table" + }, + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "yellow", + "mode": "fixed" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 2, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [ + { + "options": { + "_stderr": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "_ stderr" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "points" + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.pointSize", + "value": 15 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 55 + }, + "id": 63, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.5.8", + "targets": [ + { + "azureLogAnalytics": { + "query": "ContainerLogV2\r\n| where TimeGenerated >= $__timeFrom() and TimeGenerated <= $__timeTo()\r\n| where _ResourceId contains '$cluster'\r\n| where ContainerName matches regex '(${component:raw})'\r\n| summarize _=count() by LogSource, bin(TimeGenerated, 1m)\r\n| order by TimeGenerated asc\r\n", + "resources": [ + "/subscriptions/af342bf1-1ace-41df-902c-47921400551b" + ], + "resultFormat": "time_series" + }, + "azureMonitor": { + "allowedTimeGrainsMs": [], + "timeGrain": "auto" + }, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "queryType": "Azure Log Analytics", + "refId": "A" + } + ], + "title": "Count of Log Entries by STDERR and STDOUT (cluster: $cluster)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": {} + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "yellow", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PodName" + }, + "properties": [ + { + "id": "custom.width", + "value": 386 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.width", + "value": 200 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ContainerName" + }, + "properties": [ + { + "id": "custom.width", + "value": 302 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "LogMessage" + }, + "properties": [ + { + "id": "custom.width", + "value": 1656 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "LogSource" + }, + "properties": [ + { + "id": "custom.width", + "value": 140 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 15, + "w": 24, + "x": 0, + "y": 63 + }, + "id": 64, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "azureLogAnalytics": { + "query": "ContainerLogV2\r\n| where TimeGenerated >= $__timeFrom() and TimeGenerated <= $__timeTo()\r\n| where _ResourceId contains '$cluster'\r\n| where ContainerName matches regex '${component:raw}'\r\n| where LogSource == 'stderr'\r\n| order by TimeGenerated desc\r\n| project TimeGenerated, PodName, ContainerName, LogSource, LogMessage\r\n| take 100", + "resources": [ + "/subscriptions/af342bf1-1ace-41df-902c-47921400551b" + ], + "resultFormat": "table" + }, + "azureMonitor": { + "allowedTimeGrainsMs": [], + "timeGrain": "auto" + }, + "datasource": { + "type": "grafana-azure-monitor-datasource", + "uid": "${DS_AZURE_MONITOR}" + }, + "queryType": "Azure Log Analytics", + "refId": "A" + } + ], + "title": "Error Logs - Last 100 Container Logs entries from STDERR (cluster: $cluster)", + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 78 + }, + "id": 14, + "links": [ + { + "targetBlank": true, + "title": "Open ${component_text} - Overview page", + "url": "/d/e57b7777-71be-43a8-87bd-d917391b154f/bluefin-overview?${__all_variables}&${__url_time_range}" + } + ], + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n   ${component_text}-specific\n
\n", + "mode": "markdown" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "The akri_instance_count metric", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 80 + }, + "id": 62, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "aio_akri_instance_count{cluster=~\"$cluster\"}", + "format": "table", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Akri Instance Count", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "The aio_akri_discovery_response_time metric", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 80 + }, + "id": 65, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "builder", + "exemplar": false, + "expr": "aio_akri_discovery_response_time{cluster=~\"$cluster\"}", + "format": "table", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Akri Discovery Response Time", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "description": "The aio_akri_discovery_response_result metric", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 80 + }, + "id": 66, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.12", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "aio_akri_discovery_response_result{cluster=~\"$cluster\"}", + "format": "table", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Akri Discovery Response Result", + "type": "stat" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "description": "Defines the service Component this report focuses on.", + "hide": 2, + "name": "component", + "query": "${VAR_COMPONENT}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_COMPONENT}", + "text": "${VAR_COMPONENT}", + "selected": false + }, + "options": [ + { + "value": "${VAR_COMPONENT}", + "text": "${VAR_COMPONENT}", + "selected": false + } + ] + }, + { + "description": "Defines the service Component this report focuses on.", + "hide": 2, + "name": "component_text", + "query": "${VAR_COMPONENT_TEXT}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_COMPONENT_TEXT}", + "text": "${VAR_COMPONENT_TEXT}", + "selected": false + }, + "options": [ + { + "value": "${VAR_COMPONENT_TEXT}", + "text": "${VAR_COMPONENT_TEXT}", + "selected": false + } + ] + }, + { + "current": { + "selected": false, + "text": "Managed_Prometheus_jajens-azmonworkspace-test", + "value": "Managed_Prometheus_jajens-azmonworkspace-test" + }, + "hide": 1, + "includeAll": false, + "multi": false, + "name": "prometheus", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_node_status_condition", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "kube_node_status_condition", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*cluster=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_MANAGED_PROMETHEUS_JAJENS-AZMONWORKSPACE-TEST}" + }, + "definition": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "hide": 2, + "includeAll": true, + "multi": true, + "name": "namespace", + "options": [], + "query": { + "query": "kube_namespace_status_phase{cluster=~\"$cluster\", phase!~\"terminating\"}", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "description": "Latency threshold for health signal", + "hide": 2, + "label": "", + "name": "myprefix_latency_threshold_ms", + "query": "${VAR_MYPREFIX_LATENCY_THRESHOLD_MS}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_MYPREFIX_LATENCY_THRESHOLD_MS}", + "text": "${VAR_MYPREFIX_LATENCY_THRESHOLD_MS}", + "selected": false + }, + "options": [ + { + "value": "${VAR_MYPREFIX_LATENCY_THRESHOLD_MS}", + "text": "${VAR_MYPREFIX_LATENCY_THRESHOLD_MS}", + "selected": false + } + ] + }, + { + "hide": 2, + "name": "latency_percentile", + "query": "${VAR_LATENCY_PERCENTILE}", + "skipUrlSync": false, + "type": "constant", + "current": { + "value": "${VAR_LATENCY_PERCENTILE}", + "text": "${VAR_LATENCY_PERCENTILE}", + "selected": false + }, + "options": [ + { + "value": "${VAR_LATENCY_PERCENTILE}", + "text": "${VAR_LATENCY_PERCENTILE}", + "selected": false + } + ] + }, + { + "auto": true, + "auto_count": 300, + "auto_min": "5m", + "current": { + "selected": false, + "text": "auto", + "value": "$__auto_interval_latency_quantile_range" + }, + "hide": 2, + "name": "latency_quantile_range", + "options": [ + { + "selected": true, + "text": "auto", + "value": "$__auto_interval_latency_quantile_range" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "15m", + "value": "15m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "3h", + "value": "3h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "24h", + "value": "24h" + } + ], + "query": "5m,10m,15m,1h,3h,6h,24h", + "queryValue": "", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "health-service-akri", + "uid": "BYZdE33Vk", + "version": 16, + "weekStart": "" +} \ No newline at end of file diff --git a/samples/dashboard/grafana-dashboards/undefined-1698853744219.json b/samples/dashboard/grafana-dashboards/undefined-1698853744219.json new file mode 100644 index 0000000..364062f --- /dev/null +++ b/samples/dashboard/grafana-dashboards/undefined-1698853744219.json @@ -0,0 +1,5 @@ +{ + "error": { + "message": "Datasource prometheus was not found" + } +} \ No newline at end of file diff --git a/samples/dashboard/insightsTemplate.pbit b/samples/dashboard/insightsTemplate.pbit new file mode 100644 index 0000000000000000000000000000000000000000..8772cda1b23a26caecd3e2748e6eaa8cdc9201b1 GIT binary patch literal 102682 zcmeFaN7CfjmL~SfXq=Q;?IA2DY!V#_I5ZyfWfNLB99lRqp+N%<=?;yy-T{YP12@3| zXPj`vF&Dut@Mh*yT^&{|S{qxu==jazm$(3~I^X%uch3EBDx0qOuYUL2zyIm)e)qe7 z`1@Zzyts-uV9!>Tc=doPAs6#n^`ebRw;fwVdmm>T1%X#e9U%r@s{D;3c zr(*chEa1v!sJl{Cj0H0rB0SF^EyrAXPLiDzqL^0zuxPYi~r&8qjCL`fvfUy zAG$Hg|8n#H<{w}1WowGP_av^|DOAhv91cvH#QK{+NwDT<%>nwD7;u!T)Oh z2b4xI`u61?{$4MV&+w%mKgE|M9oPT&cl!b!{f{@<_x&H;<uif$m{7IfH$(L@Nf9r~W0fyy& z2V?SIgU|m5`22tUcYpW0-~ayae)oR{zm3=b@-P4HcmMN0{O)%@PHD6J-~a3X_S3&Q z`tHkCd}c5dfB50{Bl5$)`uV5l=b?WAzZm8}{P4qH{}%n>=bt!Jh`uc6RQ%zGzYMa| zR5chKJxPo1udcvAdq4lAx~?w@p861fMiCVIiqKzgq=#a^$MB!vzxw4*g6Q&&YI&yf z^G_zHiM$6c7XEZI_p9uy!e6!ir^XPG|(&V%-E2!{Rsmv6uD<4`tvF)U5eefj#AdGtj*mSV_@ z{P%x)MAbCD2)}eanDtqg%yUyVU{WSS{+B8G<6ku(tzgu=rZ2vT{nU+T0oKUBkUa6f z{q>Sz9KIHR{`oI+xyYO4UxHzty7OOt0SjnPK7VSx8I~WvI7QY>4S3RDXZ||;ab0}L z#sNI(0%pllgSk|E`TR06Uta6HfG7NIN&WcW|NT$!udn|T{HJb)|MX(N^!=}6^5-%5 zOaBYbPF$w}1Zj zCyRB!tnftV%aHV7zE5ikwxzGdF^vQ0WY7r#tNY@YV#vlEEYCmu0LG@MiVp@B3P}(c z^%MN-Uw|9`xvii7oo4$nU%PewMssO07bO0}m$|vX?NJ1$fA~4N39B5wS%cJOgiBiE zTqPTV&c=K=L~EcQq1l_^D&KRy829&pK%Lj-lF^&x6Ma-7H;mcDMZ{&{{WFAKX@17k z-tfFhxU}i+sw56|>cet6pCTVd3KwfHy4C$#cuOE{n>(@8OIfb^w-Qwz0W%*xQ3FX` z^D0>6SqPn1P)j#aZC{PfuP!Cw_xrgG{o5UjOxH=N45tO-H3TY0)+g%cWy0HYfddbQ zx|g2tZU#$YQ0wfGVseqLm$$1eU%fvH%u8;?%r6`+HT6cM&%@SHVw(Hxy=ZP9c$zGd z;VvApv93;a2;Sb*&D)_JFi7WCx zm?x1g2BQAQ8S&d{_!|7Sfr7m$=~ggOU?2VE&nTmEX$Bzi5o)QQ2Hi`68g8*Pfk%5pHI?# z{RRAe+g1n!$KnWj`-)Nm`4vZbd>iyYn z7k@O>|J*VE4S-mVYVfMX>Mq!y|MWG$S74G3;60igENbu~|JH1HxL^N^Mf@)o@%y!i zqQL?bWyqZB{Ry+pMbZ`d*S0vnZoha7{}>?sBSb^r0BTn}#eKI=Wy^8pEAKcl1H%Y~xsl^HC^st?JW%=du(-a<@BZ!gY>$M)Dgqo@69= z;jkFmLP4rk9?zIt<1!nuD6%o3AaCdpn-T;i>7Hx$v|H6~kb5xnkFV7=TL@h8NkN{L??XX21hs1=eFh!=WMm z*)994_Wfa=fIs+)2l^}A`_;E&&oM7v&5w`d^9z>yAO0YyoIj03I_1|3oufI6MKm2^(M(a$Bl{Q1#j=j?mx@2Yg zfn3i)$k7w74dodkTGy~i5nLA(Cg{XDy zBAVG=(`1tsR*l&Gc+GgxF|Utft{?1@3VAa6(>@gxR*){n)hZ~A)pMLOtV`Fy>z7(_ z`%_4hJ)6?yM;as#AYU?=Sdu@qce4UpTK!ZNFyB+fmbC<<$b^2k+8m!(0cHJ_x} z7=JK#^W@Po8IibBFQaVDmdTI>IH*`SNFuXIAJi!)`TOULfaMNcGu+X z1?k3^hAx-JmgLzLwArt$vO9%pA(5zZ;$aR0hDv034+4eoxfWUtnKrp8(;pA!+yJQY!_v?8gQM z^pz}9lj^Wtdv6nyIr*vc;#wC=DoUf49^NUEijttr6IV_syN0WT40_bFTRnd%c}Mo zh<0@DhzX4G$Xr*xH8@XIJwJB0r>nDxdy}~FK7~X{*x6GipBXN(J*2!#f)p7cW%^TB zA%&3YoRWzT4qj&sv}N$PTB+(6W+9z)yF&cA%;~C!fzo^qG8Mxy=k~cJ;Bs|mucq#R zoj7Ayfzd75_S^euq{(}dc4M;M;-xE(2o}+7qM>HJU-sceiSaa~3eja^w;a;BFi9$J zpHLVCwr!8}aTMDyzes$xP_GJykkPB-jl`>Y4xd_GjVhUFI*P<`6gWV}>;&j{f=lu! zGfmMU;wL>|Ywa+uS-c>Ef%i!VBY~5>uQ8vjb6q}31ySfluhml`!?30?K^fY?q(NAmPYHE#s|I%6D)?dUNHJ3lF( z+W8QBtH=a>uX)O;%k;U8WdF#qaHLOvJ53B8pL%?6m6{DLV+#!18g_l5hL#CnIdAoc zZIv)~Pp>f`e9!QqPWNBZ!nl}xll`RAkml{JX%;4a?jIAib8_iC8;0piGiKAWo9?P3 zcBftQJ>4@$nG7UEBIF4H|fn;`P>T|e7r`ze{8sYGe1m};ue z-ot&|7T?(%yoGm>geR*cS8dT$>DG-e8y=ony6sfHz{0{}`&|b!_o!3sGCL`$&<{eM zCqKTukfp%ejYDqKeos<`Fap89R)ET{h3jFn>29&6iBCx3ON8wbY9Sj$NKOciX6gR^ zAn>_PPN$3lf)eB4uJCQLkCj>QS)qE0bzOLAPB7ZL0&LEbDemshfcoX0y&tk(ddrz% zCN2hLddn2=AJhPN0-uj!$!W-`Z;g1!X?eo5g!Xq^Zt1?DF$I|w3(4f=-USy{2Cid- zj{^JnO$XKcs;iHC9~rwt99;jldK+3X_hhb5=HS^~ZaR8gaQxoXZY-&!9zd>m<%E)M zd=r=aE^_+1Ywu`^Yj*>t*;4`mYOlI#v*+XUjIE|8I%3m_3ijhpddrZfY~2#a$T}3o zehYk3oL6ry+heGuR=8R3W8>@NL~k!HqwGoP0=RWf_aCx_`!U_ zeqUt_UKoT|2E+{SqR_C(*yiDe=_Q|{-MtuWwBc}q zA41Bbs2KhBj_xjSUPQ||TW3IIC7%>By4}dYGO%@cK5v_Fx47)BJ2J0sn_*`+U4&-s zUBN*l!1A4x)hOg&ar$}R*XxO^;YcQ>bESb$H|B|>D?yQ30DnH9k7|?<43ESd6oUtI zg)wxCS~psskDSykB5lM;7$|rn2^rdExJq)OWlGmo@B5JGH;el4+H=fHu%U3iTeALg z3>(Dc$>yaWlHl6MtM-NK9LPtcyTK@~1|^eQ5J+?42EGUfH_bpXMREgOOQ_;$uWkj8%WFj_{7t~Lb>xjqU1}9|GZWApvVEo|rS8wD8R9yi zUe&7$pH*Sfnl7}Lhvj9zbcP#27Q^Sx!IUq?J~{QV;tTdR5zmRp4Oo;2olkrU7>m1W zVYf(;Lf2BU?t39|kwa@V47QpaaTzbm@KZ(i=S{00VE+ihTuFzNdhco&SYcFf92I_0 zJB+zk_m~kuY>M*6iP4Jh%RorWkj3`Kx#kKsjDVflzVp}Xg($2qVcR4Z1wEzG{D7x5 zBaM@*Dd)pXjNIhJJDjHANls@(Q$n54G|^O#WoelZwKf+~BzzwsJeQbvKZOumf7ZaCY^3JyQ=I29VE?ERfa`{ofQj>PJ@NQnFOHgdmQ z3)h{>M7|N@YV(f?ehsgDGMSs3d+5;A>4@-#T{~UJ5Gx~3finoZa9N>pQ(gaNrI1lx zTh-98#kDNXIc@b}aN^^~$i*rxemC}yVD6+8AZvPo%~DsW(9@@`D0E=r9A}ucZ|>hE z!QKf-Un{08&^HEOkEo})8T(D!COqq=CmyKM z>$aQkH#0A`(Y+v5Wu~U{UaUDWXrnaK8(3rtd$heGTT=IUvVm9mFSL-Vt$=T+!DOUt z2c6Vcx0TYlr~4Td2i-l(CF1q=V*T5RIV7+NLgyu(={JC&>8T{!g6;V(Tgiiv6jPH< z+&R@LOznR1l(DP!qcgLa&esQ=!PIgfZ^2u@mSZ=iG)n&S%t*V)d5thC04jvuNKVR% zZm>btOH4JP2G$?M>#1~hl0U-GlD56hX9Uvhv=wHXi{StV#)#6l=8F=5aYK`|Htz~) zT7_e4>Pv1-m)x~fuNK!cQQ3vIixX%!`T&-PpbnfQahN{!op{jYRQ9r?LxZN}N_Z-r zxV0XH@BGt?2xBu}S@$a4pcaewQKZBf6Io$kPuuXC4k;*W_i3`3?;<~B#;Aek2jD43 zD6r=hlKL^7o#5tu61lK{+Ra2Wa53UcJ7}M95wpc(7KNS!D)avsjp7@v3>b=DDqarK&Pj$ExP({h;Jf<_SSECdCaNTUm` zTyDiX)5T;h@lG{E)o=AMV`AXHLz*4J`I%bo(<^JzkRfTOTM2kC(CKVXY+n14JbdZ% zNRKVN!u}v9FhRk*E&={%Fa!GlIZ87Cc*XVe=aM1@l38k}*#g9IAD-|a>(8li_R1bT zo2~OPd|q$(&Z1HL@Gf*xOw@NRO68ssW6~@ITwlVppU%itvqC^YrW1X-E?r_g6hn4r z!!LN)Bc~*766*SA`DH}-vKtgpbbDO*W!bNH%ioW2 z-q<%*miWNzo%~uRBzl%dF6Fn*p)>bf)mr79yv-OhIOZ;rB!U8vo0PU2)L@?g4>(7} zP+AEu5R$<^Tu?cKQy}S}ZW>wi3R>|H0%Ew%^A?@UdvPd-up=IJN+=Y1LSI~{+OnFF z^CCQTU#4^r;x)>o(VkSu0cy2)YX*fT&uxCS_OPP2GEdi-HMR{0^hkw&6Tima@}G*R z_m1fxJ<@dN2bY62U+Wy-9O0cf4P%_@HhnQqs15W+$aOe1-k4da;seWW33{aM@m`wy zCoj|ZoS*i6#nNY!`m%7hY4+`qxSv3o#vNa@->5T`L zuFo+LI^Fu09Xd8;BAfNB-rj)|4CRWaR!{h0s*5Zjfz>&?!JJpn_YJ1D+vZ&IN@Io6 z#8p)|4`O=MpGKbbqPIyGs_!$y`_>^gED<%Ku&L}Dr@CP?4|aeVvSv~hMW1xn8A$8R`ow-B1R5+CJpsLXRwQnb)9O0rJ{N zdK9b_LjjmSp9>QOOVzeRN;uN1Dkb~MJ8`g!#Sl4l%4}v=YtG) z9jIzmBk72}$tFjdIv{7dD<2B%rmrccXffwH^(@-wR^I%Rv+{r$x5%bH&aHmBUIM&X ze2#g*KKTOen^&lf{x$--I(QaJ+_+;A1{wt*gRkg9?Y9>Rp_^ zR)&JMJ9`m1)X2*u#F5Jr+p6xz6-%pTn)_f_ZQh!dG(KC{qp2CKb_IqG3+EC-8UTmm z@R3n2uD*M)CMQ9fFzE^a*gijFACNGbT3G1S5KD_v4{p9axzd4$tO1_gvyQzv-*l-w z_wH$mZTSL0A0hSjwaXZ`1>DOhNJ;(20Feo2gwy=?=Ung|HSl=esAAqCHw(sVrw7&{2_wjaZs) zcWi!tgf`v(T{H0zK6ec^l_GuGH>Zj?0}$drtc{U2n*@Hwr=> zv-WxFh&*~$=0{T@11I{J1CK>6MA#loFNogeLNg9Z2DT4l7qIe#d98lXAg zl1rx3+kBhm;vLH$t8u+no6v_@20|FbFF$f^Jxg4CakwFU887D^Baci~r-{4FF7K*k z=%ZV~6^<#t0a#kj3YaZ=Xdkj>bY<4Q@;TEiIz$-Nnp!Yh^!0Xx1G;v1|E2mIhtkiT z-h8cinLT-FxCWdEGPL>(7n#9u3dp0+bSw#NO+#IkBM?ozcEJ6{kq?D{53@c7(e?bj z*j4TkwheCi^J;E5ASa^)g&Z<{%c|omS*(kS?BDm8BSrom-q#?xUa}iUQim@U?V`|0 z#_&h7!}-``CN%(m_3oYbg|{uiC;3YlZuYGUqnj+YJSMlR?%OenUlHQ=xuEd;J+ZTE zdd86+6TR`Qo~>7dKxdt1BM(`YMhINv#ZOFA8=Jx#!J8aD6bU`N=cugnH|AL}Z<-wU z-uRScEtgtQ;l3Ms1WM6RKH!ysYRA^x9z8lBZ{=3?p3|*-f|q!yz%!7v#YdkBUSIIG z3{1a13acJ1vpu>(j7vd29cz(##ARd8=(UU%0FlgO+fVCaHUed)WuVam0BI6sWj-ej z6s5jtzux-UI3FBtF5sNDRfu|rkKFw}SZ+5g&>D6YHjP2*)O>w-i6t#RxagQ)hE`!& zRQDd)YrYo+chW&414QEyh!t7aD(3TUHKJ7? zH)G(1C$4V~*DWPDpTG>nZj7Ocgmu(CU^*6CfQ2+&nG>O&q94QT8z~&2q51{O6I|A88F>nncE#9DL0)4u4x4#q2X{JX_riC(tQe2l6b>!d26q53o)crlU1{>CKf}xqdpfKHs9ta!zp5P5dobqFpwC zGDFq(a$}a^e&p<%%9lc0z8ODyJVk6=0CgiB-mM1qvQaJg$v|R&d}?6U8yKwJ!IW(e z+m(H-wda0T{OGx~4s@AHvK)_`n%&Q&=~9ur6bRc;HO-@Zkpb(dXQO*;X#9#vgYL$UJ5yLXxESmJ7S1!iiu0?q(;SN@uln4jumWy zCbqqg^atX!e9|C5+;@sJsx|9Au${xSZb!93P>`(1O03kL3qJ$ChnIH)-S1m;HzsZl z;@MPd`*o6Mny|J1zSgcGRqinE_ok;8WRSE#Ftt}9H$)PMV%MY#(Fm%jEBFVv_BojM zReo5lpuBQZKQmvN2Fk#oj-9QSY<*LIQEJ>ha=h-dmjv(_u}!{DK&9T*JJZAik{?ZC zY{HAbTv&t*;04NnU&kK>Aoz?WjPf+w;PkD}K2m~E;?tQP#vXo?KT74-O-R^@)eF(o z0t;3auw63heXi`=M+ynd%iDf{!I%HLca^gR12@nF|>+T#_V1bVAvbNb{nZhEr;=_C+CwCOWn z!+0t0p=@Pzo9;o}+a*f9k(TFSbC)wnV_s}qt07|6Gkg>3Z|=YKAkT&_OiElKMe*@) z*5*`(ywnj=ZAejkG*gYTTIoa6=qH2ruKp^Y2-12jEXxUHnm5*>P2!^+YDCK?0~YAz zek4tT{79p0_bP=uk&#JZ$hWISV|sYI1_Y)S0Jt_#sjv^>Njz9>1|d|^N6A>ag!9F~ zSTEQvu4_nyZ_d48Kl+_(kyR<=4CQ*~0XXd!z}u$**H3m3j)z*{Q8>Qdy5>zl#1N79 z{CrVZ?<_e=#Qlw)qF>xUXXAoC=HPVw04bGDQ*36autD9d;fW@)155gyXr5(oz5H`rL6N+4G;MVqGM5EAo!*ocG#CQ zR+2uyLqNOoE&M{ztvJ<^8EzchI^Iyw(YwDzvfY-zx5@Neo|PRNsPd{36bN%fb=A%b zVn4(Cp`h;|RdrePAuaGmt~Z7^^;VoS<7LuiX^ewx2#1WwGFnH-iN%eb}v@^oAA05gUJ#`^Q!?#UtvA(AcZle#!m&p2|mM4f*wA7z~vL zlUUfrgdF58?k~_$-*1DFeUE%^udWq{{8rmPyNHX zvJN%)NwpOjvbedH7T~?yk(YWk4JUtUE!v?uIOoh!D5mRSgGlg3oDa&W0LViJ>V&n= z9p{GXHl1%vT!B8W?e-&708rXHe3}QvsH{XfPILoZbgRXXnk}8 z`Z2O^5!rZj!fJH&HV}cmnLI4Nx+nM6a#v{`?QjG8Y9g#2*RXRqE$XQvs!onSpgYDW zN^Gl&+Qu8Y8VnHx8hZkKrd#1>1ArGo(sWyXL?UO1xO_=Vle z7Qz_h9+bp4`6v2QobMT^DkLR-kN396$hHG2(Gr`KM#m#Gktnj?t+$s`!2}3Y9Y_yh z`3=PYN8uK^LAnym5Pr&y$ukK00KreYkfaev8^drg`u9jru^jq>}kKdwraAm^ZD#O<{A zzL4S4(7N??G|Qog;*@&B>(g?v>Bv5bd$T5PlJHV2Ga)X3lV?eCUQwd-!b+$0Ts6>L5-=MQ?F^TTYl+$Mx_W=w1c6 z-0m2cd_debuG_=1k~X7aM}_AKNGmPh82Of6a2xM@m@aN!tRvO?Lw+g z-XS1&=?>~@+}f-d>HbMxfJ_%GsUc>KxwP{Yz||@;JaZS+;ca+qIEF=dgP?iu14Q?~ zpZE#W;nPt92Ru5}P=(z?mCMrk-s6vtTnbve(#!|kk~@Ef71KW{_w=pm>?x3vvPkjS z%BH4&NAde_#!pa$@D~e@S`r8OR<49+;+jw6F1xMa?v z;OQ5}X{mjXcf>xf9b^l11_IZ#fnnlc=CdW(i0f>bd+VebWw~Q`%&Q>eI7h`3C-ARx z!^IA5fvTJD{Vc2+kyEddRkHpmL>>Mpor5^wobC$beop(WrYx4SZ>Ad2Rz3od{nALh zrGM_I2d~`|)f@Lot-bA^v}wufZrvGx&ARCvmANaP54BoFyCK zpPMCiHolXy;tG~ERB9wQaC*A8o&>=#;avk|6u)Lf7kNF2>z5A#F4{uf>K6!#ZEujWHyIcZcLM@-6+@3sJ_HcU!WI06 z@i`AK>ZK+su47(wp-Ro+epp$g6DJu^n!L`geHcE!^`%(H4;?GG$+1KvzQ5X*^ycjb zVzp)sA+Jim&*Pm`=sn zN^zQBK7`gD5M&Li;Ggv$Ti&g-W9YOFmG$8Pa z_oGhZo&?p+5*;GjTide>Suk6x>YvjdgtUKnDRWuucux6B-J@+*%NyP=Y5)Q9k|%7w z$@qCuy+-X*6h+ArL@Ha)OguHg>kp4jAjNkZ-H&B=0_~_3&@6Wqb+Y%>Bx35CfeZmi zsLSv)mJZgs2a>%1WAp!k2jW9z?6=YzE?Dkn^=!gAi8D0Kd)aqq6H0*%RA?vU|8V^E zf13C=<8YncD^4{ZY}~y<1D35s|9Z&)ls^=(@op85S_7 z*s=QBh`CyneX}SzyOC$lmI!!6)q* zT^{P+qWvYXlw3Z~A?1_X$#5X|8k6Mvvz|frbt?J0@nBer%t3}C41GWPLo8Kz50)0o z708%Bo+q_r!Nhzf7YLUn7UVulw58wp=Xg!)d=|X3(QEf229vYm%YSYy{OCyqa?}3S zoLq1A&P*FBhlY~XEs1)OR}sfmGt8hIh%~9IaMShI2jat6mY1z9da`cBfWu_>;EoQ& zoa~}zzoq})zL`Ih%#fy;c0WWr!T3fT^oCPwEGTH9H#boRIa8=1P6H?wQZ;?6JjehI zd9;XM0WJ|Do_wY;#P00&y3WGhqZSRA(^Xp&QY(b??XEW68^ES@voB?UTghg=AKELy zpwSu5ATqxn{n%UvbMtsQEsQmm%xYbWKC_H=P>}x;YK~HP5zrkzGV_tG-%tEZeNBuh z9Wdg;n!v|+%Fsw3fx-ysr-}QazD#37Wjsbi^!u?tAX7C&pAnJD#`v~&AdS-N!g3qx zvEA8uZ|6)flQEKnIy17HcqsJa0_2qJ{W{ zb{v<%777pF&L8-u{_30cZzeYmF#s_9UgdWaRMv2%nKWnB7e>Z;T1R_F3p-7cPO72@FyO%_&aFs5>5F1zlt^Dl<0C57OIq#p`-vZc zVoFLuiEq+%k7o}GVJsBW$XKYP&YEPqB4c~^AU;g2DKn#uRtXmdC@HJST)%7F%JStpE7eZ0^Mmta5R}Y^w1Bl zh*jk5Jn@HtRm#%0;^S`J;mUm`ZaMDv*f|njwZ)e~v!LE^W;D<005QTrVX!lx?9YAR z_j(rcng5{t3)BRXLXbkQ`YOH7JzA;3eWs>pZP?6nn{nFo{5y|7g8Y+Ul{reWk8ves z6VzSAVhXu)NrWkttxbjkzYjF+$OVki_cDL%fY!r;rT0zuPxoql)J68AetYSm2v3fA7xb+k>SBY0Ze?R)wd{0f$ z%9-T6j&1jP@r(`YbD$r+yt^n3vX_9(|A4HY?0O)I)qlL#-8_n$c=HS-{#3<&WEE70>WrqUS=#k zcu=z%l+n3^QY9So?!uElYRPIq86qK@1)hM(`vE9KpsRZsc&zJm_AF1TEG?#;PTFo& zjnvzxylx!G!oq}kX6C!|0!hdxMinDp*4uJ-e+B+p1Y<*`e({ZZMEX9jXCg6!45!Tdegv$aY&O96pqkn_zFX9tu^ z-%tFIe9IW_shQF$PyTEtQ1NRz%h&SAWPvoU{u3xh859gqxPL$S58u|`p1}nwj0*gN zdca8`tzqgwQIvos=43YCkN$sB ztEV}+IH&STV=K_sR(<9_Z-szrG2Mki{r$v05)6~5kiZ+n(~o;IS$Csj z8H+x$sotapRLFieempDc^-Cem+*}{-yK>OSO5j7Ea<{+9`2)2=#=y^{OZW_(-gcH7 zp?LvG%6kC^ijGPGvd+-C&rjh4N})NsxE#8%mcycelH5ShK`}I`fphd~pv$Fp3;UMBCu9Tq| z^BoSLcW+2QhB#<&kQn(8IQoa|sKjA5o%)p5f4KP94&^&NLH&8>!4V45YuVjY2c-a! z44hcw0-Y>DIXmSWHfD{<%0o2r9w0Q`n>c2#{hcf!rr-|#sSAGzj9bw%g~>ajF+ucp zCg%#yj4^;0^*Z!vyCyAr1T_MV8PEb993=2sz#bz?dTGlxefAiE!Zs+M&$pxYEPS&V zWcy}^qXaP!x%%I%p8yUUikdeD&a25j62gBL6o^}ITy?e_t;DR!X91beRyeP7-=o`0O-MHvJr z?Y9=JuEP^13w!px=T9YGb!+XdcYqog9i@?qm!1gB6_mqt^uxxF>+09+Fu9NM9o4Tn zMEjA^{pgk0yYOxe$#_Ze{pfeTsUIc4iM-4}kqw4|3K``?$(CpG_!$iX9yAt7%cD#|o|slyhq;0S^5r+)A^`8ShMcVn^m5gd{sm2skonNNK8^%Jmx zg!jXGb_j$!r6FDS*lfNZ{PNBChar@1XR+D+&fm6_fZ#XO+%Xz)fLNFXhetqK67;y6 z0I9-v#J@eBq~jby4-%GmUg`pWM6ouEo7a`xo`}`(by_rt61z6`y~jW107CW>REw?( zo@ixPW$u&I&&?AY0GqC;N_qwy9{yw7|0eb8{||fb9se}FFaC=Q7jE1NqT;B~tfmbz zOq$V=&a`P-XI7iEP1>|c(^T9O_txV&DsDv(H%oEh-inHf191RuoT$He?!D*U@ArQG zxaXYTIrs7P1OM=$pEh|Xyqo0x8qcR+$KO&is$q9RXp!@6AW6aQka8oCjMyCoJ(&{Uhw#0Nq=87uXyJXVV;J;;tET``#R zv-*P!63}sp|9_kx0MI_?(5z)s$!H{=Vk?xv`tgl~*sf||%%Q+$w@DUiKFQE`KjsTj zK3d9PWEOYuoLb5mMn7Nf`N}Y^QAFx#xz~2C33;ENJv`?t2@b9m*^GReIE^A=!6FgRHf3xa}*Y0 zSTz(2da1Z9*UV%tRhE@Nl^3Nn05t_)e54mCp2)G-A%&zJUe{y7en?h`Gs?M8F@8$(4_Uu7q(8DH6_r#| z?PpQj_EH&w=D1Fd81DS&A^k&zfF0-}Rn%5Z-d{2n2|PxDv0=`?HGLyor$6xB^BFhk zHz=Y}LamgCkAE~NKux;|WlH_Jn5;+QjvhsXdYDs#v=4Lx$xtY43OODQvE3}CG5my?W2$feOcdRi3ivKduw-?M*+429%9^~4v8c?kv>fTD zm@Fs+JckTv{W2x`kIAZ67Ww!e(?6MLgdwVflv~IaZISC_;uy(WseUiylyf1%2yukRR!dy6l#=*rIEiG97+uR-l+h0R;^?CGhxC`~zQ-$GAHXoy z!LXVT&9*xr4)=^Ao{blhkXJ%Pm*6Q;u&}t^fXF}`a|?JS5H=)wP$;LlU^Syl4d0C? z>5h-c3WSsSxJ}{$6NAE>8};4B*)ruK5!LbS!~Yn6&JLPQu9QW5raP_1D_~q4G-Hh- znr)>y8;V6rR-n}Iu@9vP91dAn#BrTG?ot{=6S49jmpAOZkGS*Adex*)ij$E}KMSP2 z2q8!LhAza&HWSLw_2Ph2LsCIeB9;r5`TT%u``;+P8(f7VHNQf#Cm?Mn2f7u%{5HM);j@ysQc=PDc5^dm=vJ1^G&Q!99nfIW%3(q?Oi^{e z3~NaK=D(2Nnny*j>t#*f%TVzEI*G~-ovSIn!Z`-owRRvN`HbTh>g3vke;t4He>;9} zwWO++(p)vC$ZV1`ng(O~l5gJ3qba3qLO|ROkpsfFt(wE<{xhUMrduXMu#5z&3a0s@ zXSUS^8VEbw>*sozYSYGa(QX4|Ind)Rl`_>~=D_w%IP` zxKhG_jp5_}AW~5+g$@QnzhX3*e6XxjzCI__iGT>*%BIC09yNWaX|~E)!zX_>q`x;2 z;6bulXrZ1BWx9B`*~(U$0l+VCLQ-ufRQJO9lHB$^72I&=Z=~%E&lUnqBICsU zxSXcO2sRQMKKaL?`5Sg47;f{Jjx?HqaJxaLe1mzvGtBud^$=OA7>4hPl&xG!PX}rc zO~>>C)65rO9jhqKG7+HTmM2FrpY1OVxO_(v1|_qjt2poAK4cZ7gdPxY!?|z<$Ov82 zWio$Ae_$ibVye`sx2kp=iF%!6)X{>mxRIjWo%Ew+Msxin8-m-I`IUb-|J{0iWekv2xe8Ykf*tKzG8<*wq3fsC^DBq& z$FJvCuIE?&H~(RHJ-^a*w1nV#wP>rrMOe{PW8!*#-m+u-2ol6>?d6NN|U3AazjIceg&if6{N1q40xHwVgbb) zM*K?3a&j8m<~-4KsRWByXc>tQERr>WXcqy|kfO!KSh8zpA;@u>ByG2aa3B+iV8J%s z1(VrkT&e0}jQ50)*ta;k)!@Ba!oqM&4vDyd-o#K4qD7f4fnXq~bvc`04P z<;s9%Yc8zfDkSD|ZY$CW5DBH72-NX*Ge)=K8qTF)mw*#Z7fPt)5b>9+Up_~ACMv~S z$w0kT%D_aT+Z~dB8_+C-4g0L=YPiz#B}xr48*N*lBv-YV?$99)EW$im01+fXs$M>k7G~151J~6&W&_ zi{MrsMT%lTP7r;k8m-g)G|KWEk(Y~Dx#CD=oeYA(szxhGM0TihFOnxh1Fb<}5n_nv zUz<_0UDyn;ObEfdy?`l~vqXQG_aC*}8M2g*`WRUxY>G7>fNS`&yW!6N>`-~UKk!5? z9aP()Y>DlF>2`RS`{T`IpbAxc7F!i7KtJLt9;mbi!@Yhv*r|3hu|P*?gB7#b#B)SH zogY5+V?*;l>qSk7H;dt1F~yY&m5!QXfYLDX$Lsl;()8GOt*=yWv8b`nOd&~&;KEPA+7Nx;2oC7SOH z_xn%X(h(DFaPdkW3U*5vm2f+um{yCyolrKalK$f^S?cn|s1zGM{Me!S17V);(4wvsrljV&l{3IAohiD zfe6TfB!RF-t`e^UR-+_(iE4#uJK=J@oq{om&Ur!n4_W^mj3zZ8go;qlZ0Ff@soYkf zZrUp#fU2iJNyGDTzHI08MzoL)d#MJJu^XwFMK>$FS;*2>fB5hlhxDhrO{*D*6;-5A zDtX0p29L9T$9SJkC5nl17)V8;2tkA@QBk649pmzOA3x-uSTCx99kfv`<9>9dQ;l|+ z9ze%J^1#WqY78hU65xW^iY($b$q3k@dti#v%_M_G>H(%y|JV6jx-HdZu#Cx+F;9%gSVhh^ zjR=7k;6~XFH>$z7tM$F8+{XJ_9}Z!By9*aYUJ)2Ck;^L?I5j|h8A5=zGDtb$b0{RS zRxI!#$4h`fqS^IGMrA=D z`w_yh=E1Duqq9)8W>JHt?)N4J8388foSaATRMM=_sH7z01&2(4p*S3%<*1ycTrI3= zqMm7Wo0%q5Zr59FIGOd$=?n-?YzI zZIdl2i{+4^Q4C zgIGF2g|dCka0YcdNBZqAq9=1qmgx3!iJ%NveJ)@1P4+54bz#?Ygp6U<^R^sH8`T8b zs8?;VUkoUXY;NfFv(^zZUchUju`F648Qg*W^|WfBg9MUbf*xAR8Zts*W;*}JATr$h&+rxoLK=h1L;&bJ zDbUg)DMNx3=%p$#-KeEe0NOrFl!jBDr>%F2a|7*{Ca=uiI9&LBPoMYpjj%-f)kIC;uHo7kdA4jXU9skl1N*y{{Of? zbZGt@r;90H0cj32IU@p!KvK4qW`;Tcv!((4deCeH`Z+-NRe3D}*84~>&&Pa(cTcjk zzCvee8Ag}1KVsC2!g<)o0GMT&(=^+71-#4?hS zgXtnuF2!nyqs&OOt6|xnEvB#A>Maf5ED7fYgQBKP%;a6y@60G)gqu3 z!IO$F?Zq&^$Y$8gpCS976IQV7AWVH=CsM6J#b*`jDHICXPPdfIr9Bi(H05>=^xU}p zhxGsESTm~C@` zTNwarRe(wZDkkAH;bdW_HgHM4gZ?4w$A*kw;hvGqz%`^@5iCm$W-Cgk{+;3nBm#Z{zSYSk?^QD`ehvWzAb zuO5btysbc?iUCI2e+CHiX^2T1E!!rv5=4D+EU)f-Y_bj28o#9 z6iRTS;I%kA(ey&;fDb{T!bOdOyMY#8s@QoX1NSAn0UPW6J#x7!*({z!!d)$vQp-vp`H_W`-2MYBr+M-OlKQPBU7VWLL*p+gu779jRgb!EJBDO+N?E0`Di&^ zwK>);1QU$-Kd#?i@9&9lbi?f_2-Bn@g?z)xaK7qly}#$b_rI?9_YBehy58SYZzBzs z<7FdHmC2r`_W8_uf6ox>$Myam%??mrj0h2++ifSsQdyME_5Pk#2~Og@`oL3jZn**R zn8!sc8B9wCm^egNrBWcRl@W`H1XHm#&B+iLsDhr%;7KD2Ld8g;Cp78>H0c%+TFJul zP@Zh2K&L1V@Dd&E)}nSQRID@#q9j(iR<#tZq?r8KM0cqku6sxVs5y2X|zr3tfB)dPAy(sfwaraUN6Fz7sE@OfEbMIsiH zXui|}j94IVQq_c8HiQfw;yVF0yb8K}r*!*N1l>L4lNZJbr9 zOoGn_V|EeZuz0dt``vq93c&@XVVD8N>!G>y0LB!HZzTqz(I)x;SPqjz`DYyzrkhd2 zb2H&Q=AtP8VAVc5eEbDvA6`-z%I%&0+qRMQiTV^>Os>*hr zHJXJ=Le4|A;o}dC!0miHQ*t7*q^M~gA&N~UT^T<0`$O`tlx}TM$r{u^O^Y?k?+&a) z$UuGgVzh^r_hN}#t`jxa_Pffup(P?09FbOeol9%Kp)fC$yEo4~5cp#5Ba@7e) z!^mITw}6samnDHHhVdRi49W?G=?-`Q^N{{c%Zv?7j8wV-sswhMlB#nt&ryQ~bLl=wR%i!RX3G!%o(hfq6PBXFt?cT##C(MUvA3Kh2o2BP5s)iC>2 zSggdIG*&He`Ai{Fu5`LcxQGYcu+cRst?o)J5Us-LWVhH5Liw6$6Kpz?>NE%KHUdaO zrcg0GwH=4UeoI)^tdKxDULS(rBPQa0vJ}^lT(gw3TUId>4WygH=lNyG{zKL%J3ye^ z;lh=4#mbR6y_ls65hG3{Yw=Q9v&AN7j)sK3p7&PMpn<3mhDOP)I z#OQWvj7pZwWGljoec`A*1f#F$VdnG$?Una#&(x?cb_BV_CGY*4@g6c2PX56SC6pS@sam|OvNV?)Fr zhpvADoiOOz8?TeU(zy&>G(u7zE43uCy$C8L&P!!HIpiV8)!>|}@)YPUMN(iQx;|!`8 z5+iE#y3ynQr~D_k zpR3qHS0=m&*pLjd8>>-ZF=|CfJudORX44GdMGZ?hVNP(Ex=T4_pH~N_JDCp6x6N=G4m9y@w$5aSj2~1JM6#SOG&?>9-alh- zk4d&|DBRRsOs|-L($~ebZy$&bxZwYC{3=DsIj-C8G&z!rrCQ;X>qBgkO^El5K9nOc zI%ZUIXw+8&haJ0L$+f#((gCV+rk+km;V$=2@t1P4KbbncV4f(oTW}4vASEiBXo+&V z{)0WwwMkGFx;ZZ6V?^v`isiK|nX4835&w9^OBzvJOixXjz z6Z?MICF6I&R?`YHz{^S?Aol!HAhwZ95phM!<)IWnbt<)(skRh1$On8oC7th)W+KRo zX~pF8YzJ+I#XQzy!+xi11RrGaM35`Og+R=Ot1>5tAUBdG^S)Z4&z6d%K^c!RvgaYG zG+c|>MuSQvv&mqM6GX1sa+8&OUyR0cR6QNR6|W+vb)nYBVlgv@!5$yZb&_V()w-k` zP~1p6V0g)BuZ8;5d6$z|Ka~y01S@j`$qa?_Zn&7v!P$RZ|5u}x5Y%EuHJKckE4AnV z7C@ciko6ZSzjH;mU;%>U4h=**HUuIDNYuPW7Ed-*hh}{&RR@c;qCjU$ zjATIZS`e$kNM7LlE2+k?K`N)pNQKDyUbiSpHLGM2Pikq_wJilvI(f4mPKSbe-%)Xv z4Ypy1bmigBPY??=u#xK-dB?9DY|*W7#Wq6xF!xtkeJYodBSx!Gg?(`>sH0dxREK;2 zgV!@LGmPpmWGH@7a!j@bF*V%zJy{e+2U^eqQKjU!tmY_OE)><_vwrSXhv4@k!+iY{ zZ;6?+e20F2dBUr#N@^=w}YgZ6*5Uus1WE9FL zbbozLwMcRhXC*lv&+~?-K}1s{G0bS`GL>`8wo+NXYypjEG?;N2Igr5WcteYqfQ;4+ zf}}QN{6I6AZki?Au}Te4)lLENS!Hny9mHFKcrFl&6(KpEuGXALKaq$C7-Vp4y($1e zqtFO4j2KSQzTL1>j{+W*4t9b`JC({JGSB3Es~uWEV~HXS2dlK@%ii5`n#o&1H3#P; z*ei!fC`h-II02RDY||Fw19YHPDmC5gM)3mOjyojCvh_|NTBAjex` z8p&9;nKKiCA^qp!N+AlC3oa0+6Gk#s=kQJk8`7ViRqc4Xqt@_jk-%GaRZG_k;Gk1Y zB+%#p$Z>kc6A=Lk$7{Jz#rK-j(@2G7BeGES!qsXPYq?FC$rK=xCHyQ`IZ(l=ng{uH zx}KM;NsiOYi6#%HkwGLJQ>iqTp{iD+?0UG`2vOmVR;bGcQl;ob3Q7i}`M3#!w8?Oh zz@Spj2I4*|431(*FxtaQZKZ)|Y(}V)MlKEK(-?(?aa!(JVzOx)u#$D72p43+JP8$B z6&zN6wsS>jsQg$KxwF$iNSl<;+f5(Q2nA#9DjTqs62gVi5>*bS) za0hYuM5l%``9QJ|1yVVh;UNMm_>C2c(+7x1rCsqMOtwODme!z^Xuu>YKsyI;NF_)& zaURe*t-KGb5(601_CgJ%R8C|h-(l85k~S9$N_8pH4ABG6j)+0h>aaSR=BP$l9}JSA zTromonXWcqB(KUvDAYd(SvXwlmJsnqY-N7{RvS` z&{d3MqG?Brw6uK@rO_YAuwMoW9o!Kpd=klHZIIRhrpG zFo@f&CeSsKN@XC%!V-mI6fb1zgB;sp&|1Yz12HC*NmrP9$LMQTqZ)`wgOuY3jZrxa zB;$G^!$k9a*|U{KASoGw5%H^zY9u2zOD(op)k`ftgJjEMCRb}w#WW`Pg-viM!neu* z)|V?Fmkp#*N|MtpIGF1eqY8jFg+WW_h`JA$aaT`=q5jX)LywLGhPWVCINGNsD7id7FavK>1ZM+mr3Z-($tTc;sD zC)A5s0*<&88kfV_4p}SV>4CuY>mtUsC9dizjhqve5?a`=J+BmrNSWb*T%%TC`DU2Z zY1m)D@RfAB%pjUvFR`(Fg~0m#dYpy*W(Ovk0hwl8EH%{t=G9cB=ez4<%MHi{4^8K^ zUMAd56*SL_)RIuQkr1W6EvC8%J{SbmelcTIw1y9EEcTF`7N|5aD3FLXoR}5?=pK^F zL4E(+xBNJtCq%(SIoQz)C}?v|fe~%99x(b1kWW`xFyr}g6t&W@(;-4^G_@G01KDyM zVsa+aOr=>|6uXMp7BL*PkS3(F5Q>-l*lDd@Ck0e@W5sGp&}^sy6A_vgVlL>SKB1>U z-KpqRi&CFh;xz&ll>S3_>BctsGczEvBZG%;CP{?3?$Xd zmYu#HO7L6y~4T zFwBPeXxYK+G)fD)-A|gyoS!k`YoV~2k?=?g)ev7zT1Hy~($q{c6Sex80p@{WrcVeo zgw<+N-)*}-YK`(3qmV1dIU}XX4QZe>ObbIuvr{h0^|A)&VvCTPCI|OITEG-5Awhu~ z{%YQ@`|HY1Ck`i-V7D!mqHd72eKwaQx;5F&wmX4jT=U2VDU%RPbqG13BCs9sAlt{( z=y{}UMMMBe^mq;zOMT0weT1!zq1i;-=1rs94w zzl$s~sE3=Swk|la0-9x9%M3d~F(J@_tkdcsoN9zJRui)mn(I|6e%Zso5kM2q2qo1h zlPuGS&{j1IpH6P5?y+nSjV)Y(hj;suM6Mgor>D4gsOi-?aULYKo>E zSN@N^grO=HiAdE65wr?UKtR#o0VqlnASEm-00=4)5*~6dK_Wwzr%vYLOd2l~^VHPI zWSpV6f`5E0lgY;mvD8#9hC?CL|M*{DnViM*c#0}e`F}rXxuxi4&Gy>rxT%wQoGnsg zRe!zk`-@Y?b?uJ-_qeHDr&ASWb;7^BJ~{Z8_f4G~{OiX4`$r|QtD?xbv0Z)OpIUzu zWM8-{3i$SMVb!$G{1S3l_+_OWV=f$d7iWZG}+ziQn zB0#T)HQUlqAM1!gY%!gvfpjz_)o3h@iStU- zx@KT1>d$z-)(G%Mssqb1nC)eQ&2UF7DU|09DOtpZiW<|?t4gXOuEy8VHVw55s%QzBYwHQKBEm|2s)rb>k@P>%uVq32( z)wL6a_lMN#{IsdzyA5RaT;B{{eSGq(B)36>syp3$}J=K z`>%uGL?HOr9r&N0{QIkuQd~TH6e~(<^QiyH_2($c6s4xBOtm|XI{7af{<}BvpU3g{ z4TV!}Qnb~n5CFjwfXD<8EkN)j7@341mA`Xn|FOw`bZ9Bn)>_I`&K6BY>?nWdX#RaG z|L9=S{>^4;>OUsLSiIRBOBwBE%Tv|vQQ+S>w!duj9~~K|+iF~y`aioR{aw@b-}ms3 z4iuMv{}%c~1prJ`Wk{I-Afh+{QL*X-QH=OMi7JYT5ebTj(%*ST|GJNVbgO*my6QBUGe_%s(;Dzub#obUOxZwtG`~O{#if#=ZX4f z?ZMyf`knkuCwKknT7SC!rZez2y?OoYT7SC!rZez2y?OoY`v2{8ZSkKAFxB)!9In5- zx@X}g*PlIc+QY|$?m~B4cgwjC%-Ue=%u!E`-^XLKzBCTo_>SP6 zw=Sse5;ze)YXo}6R?k0l*y`Ek)q#m47FZ{d*UozLtr;ipaP`HVN4MDWo$D4}e9SK| zZ8>G#>>KB`NA0`p^vLv+Zy^%PB3DlRb?*uHpF>}H?>!&IgoT-(I~>{57XOYsM?r zfQNma*>BfF!_gz2-fQz2+r6>pHhyS~c>B4ZcH3mtGdCW$``P=4oqPF-_{8zp^>2Q; zBs6*a&R_2F=7)Id;Flt&zO&%jo#$Ww>kZqDItV{>&YsuL+Gw#8ykhMB_MH7TyX@wr zH_X3g#AWB%pWORuhHP9nk;qxEf+-FPl=$-F8M?#UbWqKncKJ8&eG;)Z$AB$GwzD*dl-E1+jnnu z)a&j-xx2I%p5xeGFhva|DjUYc! z341>C(t$pj;j-@Kr=N8D^5u7>Z|QFIYJSjJ3jH)9KlY320b|yFzJng!y13J_2|~9e z|M0+T@2Fb!;g7GFchaG2p1wDC^MvzvIB5Km@vk5E>pdIpvF~yE!@InF*N>B@oWJ*< zyX_dtYy*u8HpV=C2FRT=U!B!pi$T(r%j` z-F~n~X2%~cn3H|__>=JqUjbpl%s8`i0bSuf6y5 zntMmlE@!%fLH)m|P*Td%&lFN>}3BBW-*;DWv4=f)u{R;lK zk<5N?-!bkv;B)T7%U5qSZ~8m;w;#|uBR2SE4V8MD=ghu-~+z1P?`M=jXk-7SpTge{IySNwGS+*N}MHxK?c z5x;3dmOkUU*_&OaGEZIm`Yz&m`==gycEyY@mRQoS;M5PcoIi83wZ-iByIi*60W&UM z!QQ<1mE*;$cbv9j<9r*q{EbiO7p~ZRITU=ib^`kDCDWFjQH z#XNBRlKaNa*f}|UZ2#+Dh*vI|5}1D5*3T1Z4RG+7LT8M zC^X`Lm2rKSu`6yqXS>IXOW*$TD|YnJJL;1TJM*{I4=lgxR)Ifn`@}7q?*8H~yF59z zCr+5~$aaGtmy8`}@K1L~ZSm}%g%-^+c~rL6jqK}``U#!wYIp&!*7h;$DhCFuBo5LkJ<0p)RLXn<(i+rAAjJ!Gmc(6 zYe{2!oB*#q`NAbiTb=tcwe8!|h;zOi^VK~cEkC6a{$$pX^?6QyVIpoyO=jTHoY?C{2uWMGl^`&_DuJ`YA$9CLJn{2h|_PYAXYwvFS_0%cs z2k(A(M1Qk+Yi?(Mo48SLlP3e)kU!-wy7@VElTCgKUA*5Z`?klA-2Nb+;qd7A({|Zr z*L80nzF+twLTFz0P`uKTSyO{KYpTMqKsd zC;K*@d*h>J--OBi_BnIYE4C0HBS%h?=5F}ueG6u9x51fjo(?X$@4Qzh?Es@0ZFoVxdEXD^3$f1|nbx3h|Ojaq!++06wPfB5k;$G>^h zWh)Ne{H8G<+vdk$E# z-&L>N_Ulz6oCDvQ)I98^kKTGcs@86pnVgh6YRsWseB$T!%dcEE;kMl{Zr!J&r}UN{ zcI5e`>&I`f_o$cE$I27dUGp4u_Vbsl{$$>Qw|{wT%oDSaeaGuBF2>J!?bT;5mzP&7{Lwqk|82yY&6SrPip}|U)C`?E>U*_Iom>6kt}jj) zRXzLhuUEmJ-ne-D&Jzvs{I&XrO622-Q>u@Tx%9S4$G32BY?biKZqy?U?dRJ0TYvZ7l;dmr{y2a2MvFFja)(d$e7Q2_3gN}z zlh!_Ohd!8MU;3H5eC!LCv>t!uz?Y6aZjVQ<+9dJS_R-nh*kL<8d~ak;bKNz>lj+>W zT<)fw_CD;r6@mGqAH3wTWz(O@Wv|x0dGykYt<#@;PbK4vk9_6Wr?x-zj;*^_IIB-t zv-_jY2g&Mb=nI(>8n0ZLn{mriXN;^(S114c^T}tB6An0h_K7nNJbh|o(?hPC^JseF znOiKqXU3J+oXG8W_ZN$ANUb~PjroTzU-I+l4_<$2OZukHk*Dt-+Hu(>W3Q)v{`$^C zPdobEsp;kDxm$jA$EQz{mmRw0*52B=$6Rzx{+JQ%%P)R=!#Ou^`rBvlpO((s7Edhy zDIA^t*67&$S7$$a)OL^UyYThoWhaj=kLy~aw%PP~`^M)s_$_nPXPZC2Tc6m1eF^Hc zkC_rZ;J9-ZZ9Hw|?Y*lDf7P%MZsdX%xQQ|B5+V zSf_IHn5Qp%;?S?ZTN}BRJ^0K+cg-Am=9QnEI=jEuw(ccsI{Ur-)2n+2cN%}|`^Q{) z!XdwYas5p@WahK8cLqn?yK47uTPJ+_`0dhFJY6|+?*|{5`sm4H&phr01U`NClf7w_yQ?>G(H?uYn2*Bmyo24>_X z_SKpD$HN;fT(R9=@%xVXnVWUW!C!2#-;6s;+yA1@YF#>gX5v*QdNBH?{rt`ky|H9% z;KN@ITK?0Tz<%$p*zVjH7ga}n`{NzgZM7lz=5v{=qg!1n26Mk|KjXM5*WC6{sQb*? zS5j}-Km3^2Q?H|ogq_SaTSwmr!taf zzi{-8Yk%If*En*chdwwhJNmZ;yQMZa4j8wnw_)$rX|Hh`-5j3Ie6$&jpIYKyxNhXZ zfzq_YUOVyPJGWd~yZz4xOeFWXyL{lOFYFMScmDb4-N&7mT2{R4>aofAf$lP2YO-jT^5yZ@KfpJJ-K{?^DvF87q7|$W}Sbncq9Q|H8)--xS^x#B9rn7HTVou_xddH1`QetYaT zTdn#2vt36Wz17yoLBvldf1R8>=i&SAOYJ&w=AXCUWX8u|UT}5c#*OYtecpdii_Fa7 zkKVccz|5ojvwhqf|NV(?yn5CMZ0yRX4tapw=IH}2donbCztfDzf9jvTH&PmR`22g{ zTD`y*Z0h|j&s+5R11BF_ z=zW{J_w_N)-7|LvbjBw1<=5@8*=UDP;-wXRxe%n z^e?A>OTkl*J8s1WRBhHipb+;_O>B=kiW>!49 z?|u(&IKtfd+DoTV6TinVJ>c}48Q?8z&AA6IIebaJaD#u3zA$<5BiFC|>5+NU&Bf2% zHSfNOPk*-MVe3{*cqjPTFJqYEgS)R?YlWtLqkMYr!sdI~{0^VY-Yzia&d<*qQyKBr z!aMK2(5udR6$K7(pVBXpJ=>3`2DKmH4@`63yd1S%SFKqwqnwR1y z&N<@Qk6s%yPhCCo@=NE;xnRfa(_5^2d8_Th>WGt~!V5>7m1-}W@#PoK&pl)AZZGXL z7wJ9q;lA-bj?PX9K5<#}!LKVLu*_q4_JGODubsQ{Ncy?^?>(~L-l|~}^EV(rUbpg# zce<0`e(R|<*S&mkk=$?dX|FH5D7}X2?kSBt_`<`kxc~OvCO5r&#{Jjc-8z27S!=B7 z6}QGunZNB3Y%xlo_?$8z2PgwcMCnueI(~c81+!x#P%M(U@{-?b@nZKJb=9Ie@ z9jU+a^`n>WJ$3vy-Hnc{&i(ED<>9r*Zb>ZKbYyNpcbDm>zrOI5tv(+${eh<*KEgQn zLg}|vgFW2^*Ec@BOy1$%v$0z~*!k0!CwtdCW54m>j#HCH@#@eaFMPW3aq!R2{dUvK zJ5Kyy*CSpz;m`d^UvGTGPgL^etyBGdp5Cms*^2$Dw@-e2pFTe!mwn>Txzm4|P+b5n zvW(rCk%>LGKlJ7NHd|hN`2m-Wc=qPX^EXs)JoUt}m%OoL_xE?Yq_mwkd50tJUi|tN z&kEEG{h(!wwmW#k$i}CwIQ5l9N#w`RuZ(YeQ2La~FCV9#wQ^_v!#ftduiWzSUEa%k zty_2fpRfID{5_+jN0Q`$qu+aM-NJXhgJt6250*S*&0Dq4vV$JJb)VJ1kFUM=@aL2E z-)-|3m;N$k#R0cpwa?Ed?)b)Q=M$TRp5;qxxoclvck3$ot+BTrb!vOtWk;Mh4Lfqx z!uNIVpvg-nz6)OY{w^Qh`_Q>t9jz{1wflPy*1=bwy~Ew|g3z@OJoV+FXWm_S@3gO0 z_m>{<;$ben7__llBywwS( zJv{j-ZzCeH(}K5~w_dN)ejVP5_pd(ww$vu8f7olLiY~olhacbn;qZmRV~Ll{ue90w zK78Aa$AWYA{&tHemY;cGnRw=qyQjW%;Et2N{&M2tU)19beW%^@N7Q!?QxBgyelR$J zT)M-WUv4$`IP8hpyJLV~=ExV2 zn@<}1G_&xPCl;Rr zJo)s;`?n{baq4y7?>;U?Oba~fZWt4;KZ8cLdiBLoN4~yblVD_{-{$TFoxb5h^Ojfo zg$s6GY0e)1*e6#!dj46f=l!U!1(^$_4hWVC=jD1XW}W;}F5H3re-v>YD*G6;BMG;AaEA**ZwN(I8xZXLv7NRhF1Dh;zGbs8yv#jcN54bi0qDokP}nZQ*ialZekH3J0|H7P+O!M@ z$Orc?QZXRe0z)g=uO`d?+7tSOovDST;;Ckkdd)Jt_$z*UT#)dsGH5FvO~=y z%ybp0le@KB-Khi!j3=LMD>{kTK z`f1+6P7OExYUkjDo&7v!T1AH-xveL|cJqFc=os|UUxPxUjc_4RN<}M3HS6LPrbIs7 zFx=E+8Soz#fYLjA-UQ#?%f1h5>Ms(6>Zn)EDIueKS*9=m8F;(x9<%wTAZJ*IBqR@Y!I0%tc)A}=l5 zoV5}71a{9v>=2^Ltk7;NW=^g^jWl)IL7F8#pYc%wL5oGuh@kRYO@WlbS zrIrlPUsQNxV2kL(5D;sAYNZr2w)m7uci49eWaIKU9+l67n%!ypQXFlkg;*Fn>WcN;QU4P6Ww~mQV8=i%-jD za#iC@nh$_4&=OfKXtGnP3Ei~+KK|J$(~GXu=+`BfQ`}IPo+!;>Hk>hPk(zTKpeIVp zifMd7n~*tHVT;)CDU>o1TMkuHLKhH1A%%_cKC330_Nf}XP90=QRM|0*pLaoHAygjt zNU)s%?@dWJShP|W^>&t2yGUw@nVA zE}Uk~KS4~SMNA4v-7W+EfZJ%TX?gdFuUx$ODl894M0!+lBk322L;s@n9cyZ*Efb@^ zt*GJfdcA`Westm}&+3)(OhwbQeP`8=?FDvJQ*0QINPPF`fvZr%BT1?u8}n;-LJq0= zgwzNU*dq%dHU^?s3J$rp%`8WHw(pJoVB* zFywUL$D(`tK7Age?$M8;MZw@lkqrQlA@n8+N2=*t?s}X%>Dzlo)5mmvQvb9gn%0Wp+pw&Y=IT-j!QZ8ct2N) zRh#z=yw)wrWxXchyqELcPH>L-HhKLL^DrN&DNSnw_B!Yra3{)3FSjnM zUUtMXd(Xo1oPbfz=NR^puZRW+~-e+NHym2_*i;%m{Z_u zU>(B>EQ1B4!O@^ zq&6;t(ER8G2?Q~>4aS|IkBKNx@?t0lVQEgUi~PeCTCZjMaI!kC{pC^N!zc*tYp|O) zWd^zB+HhG+02N3@IS~XWufuTNpcskh5aq*_{L>)6h$h~QD~XjZCVBJPIw_FZit8q3f3%7Kk>)T=`dF<~wU-SiQi0l` zK($60D`A%Du7B%N&T;k!Fw7F=b6EHbB#Npg;Zh^>YQ6g2YfO=arM87jyxdGFH%r|I z4dtzXO}??EVfx=B-BwrpFy0>}MU#l$s%*6SmjP8ai7zd8wEG$cDiMcOkCi_YZ0`M6 z&V$x9XnSzDf(D3$Kk_Qw9uuaS!+7W0b`^Bb>F8MT^(+>+3)(h+)jlBDKwMw9yj|xH z!+CtsK@G51{RV*0Q(EcdcTca=Y2p7~gPbH!%*k88-l_t_W{#u!j+Wpsg2#dvvINtq za(WJsi@G#CpULGCeN=%yNcVG1CzDR*CC2mPnlE*Knl0i8zIjq6c3?^wTn{1BW};z z4YLP7y1|73aL|vm)nJF!A<)Tq6$%8HXX=ymZdjpq`OizHMb!u`LccnYLoR%cbN0Ps z0p+p?Em4JGnBBD|eeEqD0OQxnx;kqdmBZDR=t$-s`g|mIw^w>lgNg!ZyJxla93+6U zN!)w-uH(g%&r#`sR;gD0jwk-xw*6B9g(+;}N&(h+j>UjCV{I;>^9-2VkYoU457!ZI zMQoGfh?EYKjYv4hL)Sj(7gMF{O?u*pa@(WQ+e1=@LQ!~A$EnoRN3BpD zm=oK~%$@hqc-YG{lJuv>G-4tG61W2)V;V0ZDYw+P{|pdK?ZoHTzr6D;*c4)I4z#f& zIkAZ{LP@fjq>#R>jx`zYPK;4#`;-nkDaldKDn``|A-bW|Bw#e(%{KSTGhGt>VRe|P z)xR+nZpAXpkDxBN)uM!5d9;N2fImcqiCyVi-0$$x%&u0f=As3sHH!W~>p7L{cn(J$ zNYq5$e~lY6fD!U7frytzZUhvBesKdN_c=->_zlo}5JU*8zXfb+8Th2^K)CposZKIv z)obopbMhIJe}O#1Ev+0(R5TxZ*?br*~GS5YLy-^0reuQy+jg6e5O-$D{G_9d?FSH_ig){_-n~HN!og zul}OiWaaB5!($|9DR=b_F52ThIC$1p1|%#v=(eha9Z$ytbhSE4cL?>4LssZeQM=ss zC#O_=b6nT^OQ8J-*pT)Z3qD3%Exhzwgny{08RASIz6Bq9t*`iR+0pBkz{E%eQ=%5v znF*GnJ8@3pZY8p)l@aZXT^U~t*X9pWd}6=R6;ck_s~*tBZMepePgy@>$W}gNY1{2weG%qz1V-@kp1O%ph)((k`0vsQQCVe}d3AkNo)=YqeUf;%*R67#@9 zF~?Jq=$7=?qkGrQ=fI774fA1S zqOji0~#I>)=f=rcP?y{O066204Hn&9IzebG> z8&ou;kw#X^%(?+PlBtLju<*|IiV`9T5^7say*D}Po-j?Norot2s89;b{ga1@j}*7E zM(4#J1XyIM)S2M32_$*8Q3HjLsi>+!xRK|Q2z60ST`yzUGUzdwL}#C;HnE4v z#>zmEP`5b#`tEBUO6VDYjBhxkm*As3*&92@VOdV_gPo*^_wXyB_rg{W5l8gsfqq?s z8A8I0rs0Ie8iK4!_T~#AbR-9lHG*Q(9PpJg+4U{lpA&~tXr@mkURkVAsD%nT=!HJt z4W}(5E`cwm;q^O%W_Y9#LpbrEM`;#5PHiq+8t*jdlP-rzo~d>mW(_rT8eowr$kA|C zZ33ys&-;rmp^y!tLH~ca1v;u8y_GTH*Z;)80M2MUBOM}a8>2Uq94Y9BtJSZeqZk<7s?l+_~uOcHlwT2(u z6{RrTz>3#bwZ9~jlUj4g2d*^N_(5h*CRq|wEQ9g@Ir(QRF2VvBSKIn>c$<_oCuE&A z`zqLh=5y?=fr5v?^0uU!Bd$%gAU&YeGH$fX!efY@3G~TF4C#+?ZLi8Ul)))=|8|T< zms{(_9i(Iv%u3f*ilD;s>bBGOReh@cVKJx)mGg^@HsqGy;&A>9u*2*BiKi;-)Dnw< zWJm^xojBUBOfD82E=gukF17?X)OvnL@0xhKVys&Jz?)GsL%If}aS?j$GA3mr2@9PK zVhu5c1S4x1BQ(jC`tYM5Pt?M=5=$TBhYYp-G0l8b^h|=KJas9fka=*WAbno4n_H3> ze;npt5?owl1F80IOcOW58sO*h_CaKmCy-8c4!Rxe=_Bdm;0rXA^rkIiu! ze7r~|sGCdof1_?`VOtxf{M!gxgc?XlPU-dTg|tJR=d+~i3Et{{c9=*YvL}kBr~Alw zKoXo`!XFkfg=NALuNtf8{Xq_i1|E%6B0PWH{o>Bo7jA0X8)-_uNanr*?$;xXRN7G(x7lIe48sHZkSQ0FHU51o1n!exKX`RDQ`s3OIe+e zRd}m0<>(=Ai+y@a@o!s~yZ_dE1KpfQV4zv#DPk-M$V0k~E$=7#U;=Y2Vo+iF;Ju5~ zxFUH$rrrN!7LVI1I16!&p;L1QR`MSCd~BCcWJc415k>-b4FAZl2jB!G4R_b=?iI}) zUHpUT{YMc8HCMf&FEjT%&z9OQk6gX%Mt&Y5!dN~q54;Z3n=G&g)w##Wi70Rt07nbC zENlT@3rO5n(h<$MnnN3c+rWTsWO?i^@7F4i62xpJ03+=^Hbij4s_!NrY|mk50PCs8 z^sLEFl9-JM%TCtTHI!=zU5M}>cZtvP{McC03I5v#TUyWtvaPU18m74|XY?_-(L825 zdcAkx?BNXBr}Vpdc=vCPuNo}(Hz*rB+9A^I8953&@^_cqmdkd-gWZ67flITk*pq|L zw*A}7nfQ0GVK^eG`D}Q7ZE#lcN9=xrMNXB!6{=JG(-nM^ldPJ<1bK3hCVe z$+PJNOW_)j(#&HTPpml; zo(3`5@w+3L?QO|AeI_M+>I`25QSVJp6dg_Q{V=a(@dN?^OAV*~FjL6ij<1k zUMBa9v_iPg33iq{sQv9XiV}}*f)Tjo3ZI%M3!JzKjk#cr1n^$GY;(0z$-p8GczFvo z^hCFHJk#{aESR=LN7pgp6&KqXQcrD&S0*!B^fCrE3FHp{2_S-=9IrakOXVQmEGLKR z)E{G;5Pwq5-(s|ksno>8&oFTW6zO#~%5Bs9`52%Y`P6ulD}4F=+0-Odu~J+I{{uCO z4OYus-82pN6pZBm9Or)`;?huhkhERgC0Du=lr!)=3_RSLoL-oCQ9ss1a zX8GhZo*tbJ*+_P@D*K!B#~f`Vuvn5X%V$M6P8l7(}yM| zf#c?53;OQp1vh<9cEdlT3+HgWI|-@Tt5Llj+x?dW`$D>w4mmy}Rczb`&bAq-Z`+2^ z^wPa~@JsrFA}Hn%Rn9~n61Jel`uFZ7-PkO$uY!eZNYl0Kgr5Tx1Atkluj3H5OU)l9 z(({|-SirYV2a`*Y^8IrF$XIThXC88d z*2-?jUkUi6v%e_(a?37qMPoP(S()v%m~L-SCjp6?2-+1F5k9KOictv_CmwK@zio#X zk(G;{gB$VQS2s(waz(@|MjiY&r7pfBZ61rdMT}00)Y&+2*1?)iS1vN$uukrsenjk! zU~dJ!v&VfS_8GK-6gaK!zk^g*zW`D_O2_em@cR7?W4TgZ01oqv?qOYXf-sT2;!g*m zR9cm|Tjm=0VNWtK)3DV#9ib&f8%P!>WOwmQ{dz6rs?6mxOw}CDRJeuM;qbzkQ7-h( zD@~TF19wPQJAA?;gKiH~w6_&s82 z!Ywy0iK-irIU5n;TH#U9{%K<(>l>s)Le|bhFZ2vnKejnhP)0r;O4O2c^1rClLY^$P zhpAs+-Z3=R_VHm$1egeB+V8679a<|-1Rk%_ymle?qby{0hw&8@fg_bCmAj-ZDM^a5Gw$w zoFFr_aG=;X?R~0F`zKvp+b5zhdDYRav3GaN26Hs~!uEN^^w7a##19R_nHwa{_0ilaOG*!RC)KV6dG8uixDj3*LJUT#nJcKa>q^ui%X@UvJ}jehD*7 z$)TOv>bW*mN_uRi#*TiG?>EH&-5_^=3yUG>+HBYqE*?u2qvFZ`^)XL=w*?sUH&qU< zO~CXVY1aNvDU%davKre2H$@afN)TAL{>dv`Ra?wc4tv-@<{}XmI;n=)%IoD%u|!8 z?gUMy`)}Yl&GD-Ieh0rtqDguj8aB6oQDuv>W93B7KN3Qk%Ftb8UMu(B<+O%%Vw&qu zcuXF(uNUrp^s>WwKve!4P=+TQg&WsBA ztkVc#JTe}K>*IDxRcOkj_|aGS;oO>i$sOaQ*m|9$%SE(Y_^6|`)WS` zo%AxF6#d&N4Gb@{N2y<)W2 z=-%7L7dJi;v28Hm3bl41J_DGrskQ@CUMQJ+CX0x2{h{`dc6Qd$gV5YB?4S*hYIogX zad^{BY1k_$Wx_K)g-vt^X_TCmH-+f8j^Mlkg+2JuZHg8ydlj0_wcGr$=8pCsY$+5u zYO!eEV!KS?mMMAc8Fr)^{O9p7j+HRm1eUhJ;_`%IZef9A;|j(SY&Q=Oad#vR_w%Od zef&_WBl1Y4Jgj6rnG-%1^K>+C1UtW@T$n!Xf~G@vdHZhR+Heyf;x^zW3R(mWR2*aj z@>-m43_3g4e3ZW&1(Um9`I7<;-(DK0xJJ_5n7)FQhOtD6o%*&T+SjV?t9%qQ1~=bg z#Beu$0&6-t=kG`T%sU)PVKeeEkSVP~HpcVemzYy!Mt%M_RmV6yP8`J3N8Z8RR0jM< z=8<1H-9GwI)vjEtjzR>?`1{}Bc*}Yu+-hDGMNk1b3!9@7sOO1-7TB9C?$Tn**rb6G zQ8iz`_o4SXKsBYiKv08XC`XAn#D={&B>xhZt#P}K%A2z8HGg^N3eT$72)*=mXxR8hHgaw+5N*rj# zN=%Mp5f9@o`ymE#bD%)Gzvz8+Dl*q;CY~BX{*J;)dR9EeZOGRU(J1<730N(>RH~G( zCyZO+aTw2>oxVWSH}KiCi5R$P;YE^P3(IJ%MP%j$%BrzXAHkGQv&+uDjf{Q_d+G9c zrTOJ+&UwhvcbC?(BXygAYnzHwU`J}U(s|t|HFZCiR+37ZVsL`q}9@iOW3;JoX z7}65BdWQnoSq|57+;Uvsz`3R!fNAuQrKo4;MtPjiZ=iya+N!A?A-w-z(^La)1@x#~I*OF7Bbk{iL#AIfh|JhSMBp%P_P0~!Vogx0K4g%4T zT^}3nzM!`!a&Gc~0lATBJt!`^zNi;uqdw9Wm1MN2nYZVb3o2McGwAWEE_Y^+lMDl; zQd{4$rKoXeu~H9@S)&yBjn8t~7lrqWvNy8R=pXO|LYb1?(?-v~m{+wA&0hXIcz*{1 zNg%B#4)QNCa1JyeK%7X8;vjqFo!<><+_FkkK<^8nbJx?6so+a|cHkTtDw`ox^p?)y zxi^m0Z)4Jx4`CH?b)llketYhHQknDtNpPG~LPUAK-ByN@D<&Or+Y8_Ph zrPRx4P+G{WdS=uu$;aMuQ^gD;gL!Hrc{Wq9^dO)uhIv{8^87`%JGVe7MJf)Yd@T|U zaSmB0p;A=JBMqDQoEPX79lHDF#m3pdH@=^WT+qQjzg&!yg<-DE+IH1RU^^*{(m1{& ztdp=WYs zN|-1QDw>@1jDfE6{yDBdTr;y2qv??MfxQTF9iZG4wv9OX2%_UpZX8rq3`-zO_baI( z6>ZZ@CDcj|s_!?3%b{UFWz|hZfaUpLRpf|L#^|g z&6ZC*dmzeVHm6lsy&vI)b9;n+nCwC+>N(j&C)*VE>(%9$bma7Cezu*S08PwYzAl|3 zCoouI`M6G{R7m<_{tJYAit#GS9J$cgQhT|8Rn7&Q+_6e_!-@6ep~x3 zI*8M2)9-8ndV$ny3dW4hB#KzqQOW(MAZXd$$Qon|B?KhuhNye#0z3W1(qA(zc^=VA z7#&wPcMZN&!dDGkl_G9#Xy)~=LJS6oqhYFftI{pXO8D@fdyb&uv-w#5b?O{2n*a!+ zP9#uX$sMXZwHDG|gNbi1Rc;<}0B9;2W9peuki5`DdQ zE)7ThTR;{}@D-xF%1seckE)AlhmR{Ul`wAb&lC+oRp)*>62!#1boWoEN(ik_rwp3G zK>Qze4-JB=0eaTH<1L}_+dP9AA7(@i)nK;PK>PpB8K!iI%3O9Zw}MXH(JOZPgD--b zz2`k?(?obFejNxUnJEG1@ghb@^QsWv6+fRVa_byhoK|%1jN~>X3*6)~H^WSBad9~6 zaymkAVyad@@`RZooUW5Dz1Qm=F_m0T&=`k`SoVf`7%ZUwHw?o!j)X?XBPfM1$^8!B zZMKS&w6e_u$qD8g6S zSK8dgN&Ry5Q`Xf6dK^+$f&&aoAZ0?`5naC|I?&;I90L~jaa9KO3BIRKM)Ksa*o1|b zxypHh$^>A6q1lKH`T_?!yVMghh$BlD=}sR%-Htj_R=T@kKh#&e!BSNq{WEghQ?djV zc*-5K!~|i{!^uy`i2ZBX+$!}o3OzNwFqUt|V>o{nO{)&ih;`!Zl&xtY&8z5|_Kn?p z=vYU3U)qX-Xh@~}B60Kwo5s`R;jkik^0()eB%|MeHv8eJ)WV`0G1=Fs)nVTr3@SH9 zB$&{nPTWHppKy#o(v!k<`Q&7Lh&!G@a+7C?IMVVokoNz!4P|1+E9uuyF9e07U`KvE zONq5kL^r%Q5{N0Z3!8JM&sE405nf*Xh+J}-aiVCcu*2y>P&;zS+@1IohN7e}OE+^tIQ z1l6!G7`LAx@U#lntNg6_&=JJuFu)N1$vBx3^}$Rmbj1pEgOhyxVbDWukcePHJWD!Sy6O zg7+{N%_-$k^ZlWEe}Q0P)wspsS^=0xn=QDs_Cjb_FNrcLGDo~--1z3=!e{xny~zf0hQ(Zyew6=@ww2^5v1WYWg|4J~2#gN6u8 zMNG*Rc;W|7T(kjMqS2OpV>~tuUT+7p47lMKu}{yZZ&|#{|4gYA#}@09zl2@NB=qqc z43+#S&|n4nVLtbbeNM`mzM3Wy;$A%)@{506*uczi4y46ibze4h(Fl2+r|<(ncn^=q zZAhUkqyu2COC@7ni%cXn4>jMaGN4o#4}ZoZ~Qz%6odrvOUZ&i1Lwvh^~jXtX^{a z+u+_qQw_s1|>+#l7&$^KeQL$Zki6f zL@4(?O3obVG}2sQy|C6-bPDHBcR<%pYOnb>-lh0x|2B}n!tHk#=*1%9|^UTRA9K>lw9I1G<+gIy{+ zLHS?Es&n2_mV1-=gq#}kVSD_<-1%zn2Z?=A!K5X$l2P zGR{g{f^Z~|aSgVWsK6fi(c!X#)C{#gX3Fx<+u`B15v*bT838a_B{rYU9x6Gy;)9B-grlG!BmHejmxU<$HB-XQ@Uz;F~IYm;CGeFEU#lXaFZb6Ew^V z=MHTs^m)%e%FU;;=jK6V(t7BXj04zZg%oEn# zhN;Gw;eXoW=HU{mCr8_ClL)b4K&}R^&%ZL_xUL9c&jP^*!|6M1A#~`HnP4PbMz3wX z@4>r^gn}rH7?G@O z(R%}UTrI78v*L@Fh|sFw$eNHZ)C?3raRu2@^ za1zGGx&lu4O3D-3qHB(C^X?%A*Uy7(4f1gjHL!z5P$o#k&nK3)Bo?klz_t5JUqCWq zrh!?`)t`D9vsHLl!a;r@8~}gf`b)64j zI9 z@4?~s!xb^~?{qfM6nG2)rMY)&h3H_U7<@Wdt+LKg^ep9{XhDhxRQt=2H?P>z3x`0? z?UWI75ytH)c^gna8u{xv3>mbcx19BK++0VM@q#QyNl?n6@`$r-MY4%6Gk{vV7{H?x z>zT8UuoS$>6!5({7BVx97K){rM4Jmo?YpMi`uVleE7G-)GEjKUy&hwKZ^oa#%+_rh z*p_kDK`Pj75Sx6Q+TL#^6YAZRO8@Rso?SQ&uXc!T3tNE5slMf2T@IFR{+4T)E%X9t zpEg3PtS8mbQ_csjMZ-Pr9hKuK>ZQp9C|ojL1raNowK`&Kkmyg4dn7bZ#CRtJm#sY z9*~s<}OQ7>pTJeZ+|v=qnK8yLP)7WgV&X;8@kT18gAi22Ul zHobkE3=zwsCs#Z?${*mlz?-A#2-)ROXFYJoLJIzA%3hm9d}`dY0)hoFWj^_BWjfyL zWB6>|P8yGhdu!H$h%T4@&Bk&?Ts$I5d59wdl5- zTpRP8J+k|XaT3s-(P!MzMuN_lukl=@Vp?-H@+`0`O=OpGt9C=mR8^jlIE=_^4dL0{ zq=l}e29wqPtqcC&*ffCRf&}-8T~hUauXV^k49U+0w6-^LF=dQWL}x{ZG9 zt)-1)sjb_El}otoi;qS_>#SJS%Ng@X(6!D$jO~^q2yieOSKO>8mgu49RXOqQm=t(a zR-&SjZk~#R+vRU>`H21C*(+PIkz;Fhmj}(N6bC@xG`r5~4p2Y{8{2b@KpfA}9cc+v z@`4GtChH5bfb_&*tzzCTMj&T3M0IB2&D}{;IrQtD(o@Yv#b~MlaF#hHWdDM^J!)=I z-uZHy(ytv>oQD<5%3wB{Xu9%4vCUePU_|3HJGYO?Gn9v?WK)4o`cFZeg?E}VPEZbZ4u#p2CuWGK1FMKL>d# zX|UC0oDBCb7eUQoU3&;t+rpc^VAvb$~ zuMTsjES0ej(|+3G=8QAhgj(+{e0V=@(@IP^<1!HT*H?7C9^2bI?v0JN^TuleElX$WLa&RF?aX17^enbAbW=-Xvw zH_I&BL0hX!XZ*4Esf{pHhsFqfd1f6K$pfOf$_n~0ZzGtdPci?t3L3A38(2BE^zUbi zMh4igADl8ZSf2=f7`V)~2 zV}rpo`lJ6n&b}$S6_;pnj!LSw!ix+VvjKnWlJ^in*ZBPt$pR)5O;QfboKRU$-))Kzt1GeT;N02f2x6zk04PEhU2OE%9FXHi3T1TaHlgdg@c zo_~j;^_O_-)f0}fv!ut0!Z@Yvewo1CvZLu2hqT8 zBy5`BV{F*5VN;aPw>igLHPOmSN6nkv1rGR$Uda?isHX!7P)@!Dm`ZK?b8E}(JqPlu zRb+3`t+|19J=KX0J8J(u++@C@u8*lxKvB)1%lNyat~l`1FV@E-_Q?o8oru_rHOR|Y zzV=tIscv@eVV9ue-?T$QIha_!$z+)|1aY}sr6=vpyq}^Nb|FH=?&kZ4cX-tJK$prQ@2xr^YTi)Z=fwIw|CuI!IQ|ceC z6?dqwDbcW3Bp|V3y%^JO{Hr8;cu(HA zZ4pGV4Lr%6ViY@k1Q{rWv&)p~X;0 zF`d@l4?-`PYOJ=JS)R&5@-41OwuMCyq>;i%o6c|XMHkq@>)UBwIUEQIWuSgxdLKmL zFQ(nQ@+(=H<-2Cg<75G`$Uz=IRm!Ft4iZAtk|A{P{MV4e=cBS!DcgqY3 zZH8ccS-12*2YP$tay{*E zzgBYjC>ydef2Nqg*uGfwZ zv3~11THuhYWC0qL{tConjSS$iNR=Y6MU{7}JPV6+`F-%^rX}03`Qu{TNpgNMh|hd) zg=lpi%k@A<0fE3RbhyDm74T)_Yr#=jRvA70tZUF!+S+<@ie0ZTb(!dvY2^mhb`ke` zc$y8-EMM=h(5}xclIchsFFv16Nz+cDBnq=CVa*J*8uv52o)h&i$_=Ov3w6)}H$&e0 zHrt;_`Mp2T=!>(GOd(%RGr{=T?&;`$66W#zw2`#`S!JLXF7GryX^?w60r;|5W;(o7 z>rnB*c_?RkxjkwKZlqC$QkN#&y`K20`nkGXyRc1@biPM)57%*~ZraS-)f)A5M_xN8 zn^;c^kNv5TSZ&JTO*=1JFIWLB{Fk2wAu_GP$9U+FHH5kz04YQ)&@t}o#Lvi{vQ zE@BK`j}0atLE9THXw|fK!Y6=ZjTHETLyJ@i+e-g)GW2@d#;xbFiPv|vpaf#;{l|t24}*lE+JViVcXeGCaoWtp$H-3qi! z1Ww{x>*4$c{qjSX4k!(Yz%MhH>m!gRVLSA-IQZTKEQQqFffTtLVSECJ=ct+`EB`s(pi7f;cedNf?^CsLIqWS1?qq7<9XJa=lSi^XJB>06l<*8LL(E zV@8qXLo9cqpE0Je6du)6c87lyY)|V zLFGAdIyM??$ZFV*>-3G;6{bIJt^kp)B@|Aq4#kRY}JPnhcN`+AtV1E6W7(5Ub^tVY6b@)j|WsG zq`|YwVxyQ^%nzopw6J@zAbRmNM;(?|k0|C-&vJIf0r|N0-=drL&fC$zFf$FLm-5_g zor0PTw}$M&`Q9lAOI(hC(gIspK4M3bE2KD<7{huCPF~yS0sezEp4;p{tb4ZBpiZN~ z(Q>5NX3n^!-KXZ1Io7kZ7BUdKBJ)8o35B0(?Me?h(WkQut2G}~zROhoi|G0ql7#|n z&=li_*YE(b$JI4CUh3QZZ^j->{i}=*FLr85Jn{MbKTFBRM@IYwVbCuzzFZ}vmKSQe zWMP1Eq)v@NDKG?M$2oINL;8j!m-O9y8RL$Uo#>shCxE`mtPWq9PvUIbF%8dj&(VWo z?>Bn*ib8AzVGnS+d5xd=+GZcpc44G@p*fAN5M#UiJTb>(EE1u|_cpm1ytpUulvx@* zr{Io!=4{IQ>GbdTSSu4u^lpc>p{$-6mM{{hgl=ydn#Kamka2c1&Apm zT1(k@J$ANcu80(MSs&L7g)E!<$wpGN3%;WB>;>qYb+{51S z4Qmu2pjzlj4|)syEk_>$rVNvoY+ZR=tQ7K>^sU`WsqZoBFInXle-Ie1^y3p)NRZJj z{W_BCqmltD2jBmFC8=X3b?qO~Z1e6`ID5waIf1KM);Y}JF;vqZb;Vd(O}YXC>E1L^ z(SY-9LnDxs;3SA=UcRonMbJ$6aCk$L2m#fpt>F*YFr6}*P*H>A-^JA?|DU2TDh-n} z^|1!?!Vf8F!FU2^WdJ^gdnk(C%Sntb(}wHC-a_-j{yzQjJxZsVo5bq*60UdO=yBT+ z))mcwks4t;cI=y^Ke_~LiYAbQl?{um1&uW>LPla=)ID)H~^E^A^04a2HquSL0ev z$mto*q>0~)umsMDrGm$+$HG3HUgC%R%H&j?P{u@hS066f`uR;;k~C@2Ae+LEvU+tum#=` z>_BGT=9}wJFKdb(w(Y|aeF1QLMvpf78XH|&s5r2Ph51-^GNqS>RcKr{^WjQHbiAE<^iL>1ULwx!Q%?H_zp2iXxPyKM9QPU)@~PN zu&b8;VNfmrNsH$1q{_^Rv*uT9=VDnlF9)J8ZeA4bl>xT{Nc>UuRNk&fgqvXVC~J?1 z)Z~U`c*stCXI*3^O5gw8&L)s9A(NWGs-I{hs`^#lHS%+Kr}3EFpG^bz*;`0Ed3S`j-@`v9~9}zIV}q_&3B^ zyi32xnp4Dip3=*w>KP=#CK=TplpDEbm!bgiD#qhgSG3WERS;BQbg}jOQLqKXfKals$ z$r1xIuh}fCWBZ{SULP2CK-R_rd522edxMMTdA@ps_6vOt=W62aV@@QP&mY(t-g^PK z0RsR-gcxEM3Xv6V(8B6>IH5N{BZ;eBG&5)*L5Kq&8j^hV7ehf~J41W3@yd)n^AP>A6@Q3Fl#yrfjseO!zm1hHZX_GB_z#F#f(Z#lI zNY(bqC52}rGke{<$&JdNDyv}n4aumG_Zs&C}kS#SoQDo-L2+QoA5 zvrR0L7yA_!V(mhAbNps#CehK#6p!a2g#LZ@@zeB=dw=5XB#n`zUR1|39zY;n9`86s zevO`d=#wBgZ_EW1Pw4+jJ#{p7v1@v>q$MZs(&7sPb}`s1f9Z*)J)z!nM*th<%00t7 z4|z9A{t(?e$uKJ#hN1XBoiFRsEYaGAOJVAexspMQrt}(f`)eF@C&p|(G|)dI9b1p- zP{zun5UXm88z(hUn-S6*A@<7w^X?8TG__asset_`. TagName is a concatenation of SiteName, TagName, and the tag ID in the form `____`. + +As an example, `/site0/site0__asset_1/site0__my_tag__0` would be the topic used to publish the 1st asset's tag `my_tag` for `site0`, when using the JSONTagPerMessage format. + +### Configuring Equations + +Built-in functions: + +1. **sin** - _(x: float) → float_ , returns the sin of x. +1. **cos** - _(x: float) → float_ , returns the cos of x. +1. **tan** - _(x: float) → float_ , returns the tan of x. +1. **asin** - _(x: float) → float_ , returns the asin of x. +1. **acos** - _(x: float) → float_ , returns the acos of x. +1. **atan** - _(x: float) → float_ , returns the atan of x. +1. **rand** - _(x: int, y: int) → int_ , picks a random number between x and y, non-inclusive of y. +1. **str** - _(x: float, y: int) → int_ , converts x to a string representation, with the number of decimal places specified by y. +1. **concat** - _(x: string, y: string) → string_ , returns the concatenation of strings x and y. +1. **randstr** - _(x: int) → string_ , returns a string of random alphabetical characters of length x. +1. **now** - _() → datetime_ , returns the current time. +1. **delta** - _(x: datetime, y: datetime) → int_ , finds the delta between datetime x and y in terms of milliseconds. +1. **int** - _(x: float) → int_ , converts the float x into an int. +1. **float** - _(x: int) → float_ , converts the int x into a float. +1. **after** - _(x: datetime, y: int) → datetime_ , adds the number of milliseconds specified by y to the datetime x. +1. **abs** - _(x: float) → float_ , returns the absolute value of x. +1. **pi** - _() → float_ , returns the value of the constant pi. + +Symbols: + +1. **start** - set to the time at which the asset began publishing messages. +1. **x** - set to the message number, which starts at 0 and counts up. +1. **site** - set to the name of the site. +1. **id** - set to the id of this asset. +1. **p** - set to the structure of the previous sent message, and can be indexed into to obtain previously sent values. + +Valid Constants: + +1. **29** - integer values. +1. **29.1** - floating point values. +1. **"strings"** - string values. + +Operators: + +1. **float + float** +1. **float - float** +1. **float / float** +1. **float \* float** +1. **float ^ float** (power) +1. **int + int** +1. **int - int** +1. **int / int** +1. **int \* int** +1. **int ^ int** (power) +1. **int % int** (remainder) + +Example Equations: + +1. **after(start, delta(now(), start) + 500)** - returns a time 500 milliseconds after the current time. +1. **start** - returns the current time. +1. **sin(float(x)) - (1.0 / 2.0) _ sin(float(x _ 2)) + (1.0 / 3.0) _ sin(float(x _ 3)) - (1.0 / 4.0) _ sin(float(x _ 4))** - a sawtooth wave. +1. **p.site0**square_wave**0** - the value of the square tooth wave tag from the immediately preceding message. +1. **randstr(rand(1, 20))** - a random string of a random length between 1 and 20 characters. +1. **concat("message - ", str(float(x), 0))** - returns a string describing "message - \". + +### Other Notes + +1. If you enter an invalid equation, errors will be logged, but the value sent will be a constant 0. +2. If you attempt to divide 0 by 0, the result will be 0. +3. If you build an int too large, overflow will occur. +4. If you build a float too large, errors will be logged once the value reaches the infinity value or the NaN value. +5. Order of operations will be preserved, but parentheses are recommended. +6. If you return p as one of your return data values, you will recursively build a larger and larger structure until the message size will be too large to send to the MQTT broker. + +## Metrics + +Prometheus metrics are provided by the krill simulator at the port specified in the metrics field of the configuration. The available metrics are: + +1. `krill_entity_gauge` - shows the count of each system entity. +1. `krill__asset_publish_counter` - records the number of messages published, labeled by asset identifier. \ No newline at end of file diff --git a/samples/krill/cmd/krill/main.go b/samples/krill/cmd/krill/main.go new file mode 100644 index 0000000..566b042 --- /dev/null +++ b/samples/krill/cmd/krill/main.go @@ -0,0 +1,201 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "os" + "time" + + "github.com/iot-for-all/device-simulation/components/broker" + "github.com/iot-for-all/device-simulation/components/client" + "github.com/iot-for-all/device-simulation/components/edge" + "github.com/iot-for-all/device-simulation/components/formatter" + "github.com/iot-for-all/device-simulation/components/limiter" + "github.com/iot-for-all/device-simulation/components/node" + "github.com/iot-for-all/device-simulation/components/observer" + "github.com/iot-for-all/device-simulation/components/outlet" + "github.com/iot-for-all/device-simulation/components/provider" + "github.com/iot-for-all/device-simulation/components/publisher" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/components/renderer" + "github.com/iot-for-all/device-simulation/components/site" + "github.com/iot-for-all/device-simulation/components/subscriber" + "github.com/iot-for-all/device-simulation/components/topic" + "github.com/iot-for-all/device-simulation/components/tracer" + "github.com/iot-for-all/device-simulation/lib/env" + "github.com/iot-for-all/device-simulation/lib/exporter" + "github.com/iot-for-all/device-simulation/lib/krill" + "github.com/iot-for-all/device-simulation/lib/logger" + "gopkg.in/yaml.v3" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/rs/zerolog/log" +) + +func main() { + err := run() + if err != nil { + panic(err) + } +} + +func run() error { + + fmt.Print(krill.Krill) + + ctx := context.Background() + + reg := prometheus.NewRegistry() + + flagParser := env.NewFlagParser() + + flags, err := flagParser.ReadFlags(map[string]any{ + "config": "./config.yml", + "yaml": true, + "stdin": true, + }) + if err != nil { + return err + } + + unmarshal := yaml.Unmarshal + if !(*flags["yaml"].(*bool)) { + unmarshal = json.Unmarshal + } + + configReader := env.New[krill.Configuration](func(cr *env.ConfigurationReader[krill.Configuration]) { + cr.Unmarshal = unmarshal + if *flags["stdin"].(*bool) { + cr.ReadFile = func(_ string) ([]byte, error) { + return io.ReadAll(os.Stdin) + } + } + }) + + configuration, err := configReader.Read(*flags["config"].(*string)) + if err != nil { + return err + } + + lg := logger.NewZeroLoggerWrapper(log.Logger, func(zlw *logger.ZeroLoggerWrapper) { + zlw.LogLevel = configuration.LogLevel + }) + + lg.Printf("finished reading configuration") + + exp := &exporter.MockExporter{} + + lg.Printf("creating stores") + + brokerStore := broker.NewStore() + clientStore := client.NewStore() + edgeStore := edge.NewStore() + formatterStore := formatter.NewStore() + limiterStore := limiter.NewStore() + nodeStore := node.NewStore() + observerStore := observer.NewStore() + outletStore := outlet.NewStore() + providerStore := provider.NewStore() + publisherStore := publisher.NewStore() + registryStore := registry.NewStore() + rendererStore := renderer.NewStore() + siteStore := site.NewStore() + subscriberStore := subscriber.NewStore() + topicStore := topic.NewStore() + tracerStore := tracer.NewStore() + + lg.Printf("creating services") + + svcTag := lg.Tag("service") + + brokerService := broker.NewService(brokerStore, registryStore) + clientService := client.NewService(ctx, clientStore, registryStore, brokerStore, siteStore, func(s *client.Service) { + s.Logger = svcTag.Tag("client") + }) + edgeService := edge.NewService(edgeStore, nodeStore) + formatterService := formatter.NewService(formatterStore) + limiterService := limiter.NewService(ctx, limiterStore) + nodeService := node.NewService(nodeStore, func(s *node.Service) { + s.Logger = svcTag.Tag("node") + }) + observerService := observer.NewService(observerStore, registryStore, providerStore) + outletService := outlet.NewService(outletStore, formatterStore, registryStore) + providerService := provider.NewService(providerStore, reg, exp, func(s *provider.Service) { + s.Logger = svcTag.Tag("provider") + }) + publisherService := publisher.NewService(ctx, publisherStore, registryStore, clientStore, topicStore, rendererStore, limiterStore, tracerStore, func(s *publisher.Service) { + s.Logger = svcTag.Tag("publisher") + }) + registryService := registry.NewService(registryStore) + rendererService := renderer.NewService(rendererStore, formatterStore, nodeStore) + siteService := site.NewService(siteStore, registryStore) + subscriberService := subscriber.NewService(subscriberStore, clientStore, topicStore, outletStore, registryStore, tracerStore, func(s *subscriber.Service) { + s.Logger = svcTag.Tag("subscriber") + }) + topicService := topic.NewService(topicStore, registryStore) + tracerService := tracer.NewService(tracerStore, registryStore) + + builder := krill.New( + brokerService, + clientService, + edgeService, + formatterService, + limiterService, + nodeService, + observerService, + outletService, + providerService, + publisherService, + registryService, + rendererService, + siteService, + subscriberService, + topicService, + tracerService, + ) + + lg.Printf("parsing krill configuration") + + err = builder.Parse(configuration.Simulation) + if err != nil { + return err + } + + lg.Printf("setting up metrics server") + + // Set up prometheus servers. + promMetricsServer := &http.Server{ + ReadTimeout: 1 * time.Second, + WriteTimeout: 1 * time.Second, + IdleTimeout: 30 * time.Second, + ReadHeaderTimeout: 2 * time.Second, + Addr: fmt.Sprintf(":%d", configuration.Ports.Metrics), + } + + promCustomMetricsServerMux := http.NewServeMux() + promCustomMetricsServerMux.Handle( + "/metrics", + promhttp.HandlerFor( + reg, + promhttp.HandlerOpts{Registry: reg}, + ), + ) + + promMetricsServer.Handler = promCustomMetricsServerMux + + go func() { + <-ctx.Done() + err := promMetricsServer.Close() + if err != nil { + panic(err) + } + }() + + lg.Printf("finished setup") + + return promMetricsServer.ListenAndServe() +} diff --git a/samples/krill/components/broker/broker.go b/samples/krill/components/broker/broker.go new file mode 100644 index 0000000..01c8aea --- /dev/null +++ b/samples/krill/components/broker/broker.go @@ -0,0 +1,59 @@ +// Package broker provides the implementation of the broker component of the simulation framework. +package broker + +import ( + "fmt" + + "github.com/iot-for-all/device-simulation/components/registry" +) + +type Source interface { + Target + registry.Observable +} + +type Target interface { + Endpoint() string +} + +// Broker is a representation of an MQTT broker, containing that broker's endpoint and port. +// It also implements the Observable interface, allowing for monitoring based on other +// components which use this broker. +type Broker struct { + Broker string + Port int + endpoint string + registry.Observable +} + +// New creates a new broker, given an observable monitor. +// Optional parameters can be set through the options function. +func New(mon registry.Observable, options ...func(*Broker)) *Broker { + broker := &Broker{ + Observable: mon, + Broker: "", + Port: 0, + endpoint: "", + } + + for _, option := range options { + option(broker) + } + + broker.endpoint = fmt.Sprintf("%s:%d", broker.Broker, broker.Port) + + return broker +} + +func (broker *Broker) Endpoint() string { + return broker.endpoint +} + +type MockBroker struct { + registry.Observable + OnEndpoint func() string +} + +func (broker *MockBroker) Endpoint() string { + return broker.OnEndpoint() +} diff --git a/samples/krill/components/broker/broker_test.go b/samples/krill/components/broker/broker_test.go new file mode 100644 index 0000000..0f694a9 --- /dev/null +++ b/samples/krill/components/broker/broker_test.go @@ -0,0 +1,30 @@ +package broker + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +const ( + MockID = "MockID" + MockRegistryID = "MockRegistryID" + MockHost = "localhost" + MockPort = 4000 + MockEndpoint = "localhost:4000" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestCounterProviderWithInvalidName(t *testing.T) { + expected := MockEndpoint + + broker := New(nil, func(b *Broker) { + b.Broker = MockHost + b.Port = MockPort + }) + + require.Equal(t, expected, broker.Endpoint()) +} diff --git a/samples/krill/components/broker/service.go b/samples/krill/components/broker/service.go new file mode 100644 index 0000000..d8c1b1a --- /dev/null +++ b/samples/krill/components/broker/service.go @@ -0,0 +1,48 @@ +package broker + +import ( + "github.com/iot-for-all/device-simulation/components/observer" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/lib/component" +) + +type Store component.Store[Source, component.ID] + +type Component struct { + RegistryID component.ID + Broker string + Port int +} + +type Service struct { + Store + registryStore registry.Store +} + +func NewStore() Store { + return component.New[Source, component.ID]() +} + +func NewService(store Store, registryStore registry.Store) *Service { + return &Service{ + Store: store, + registryStore: registryStore, + } +} + +func (service *Service) Create(id component.ID, c *Component) error { + var reg registry.Observable + reg, err := service.registryStore.Get(c.RegistryID) + if err != nil { + _, ok := err.(*component.NotFoundError) + if !ok { + return err + } + reg = &observer.NoopObservable{} + } + + return service.Store.Create(New(reg, func(b *Broker) { + b.Broker = c.Broker + b.Port = c.Port + }), id) +} diff --git a/samples/krill/components/broker/service_test.go b/samples/krill/components/broker/service_test.go new file mode 100644 index 0000000..3850d9d --- /dev/null +++ b/samples/krill/components/broker/service_test.go @@ -0,0 +1,74 @@ +package broker + +import ( + "testing" + + "github.com/iot-for-all/device-simulation/components/observer" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/stretchr/testify/require" +) + +func TestStore(t *testing.T) { + store := NewStore() + _, ok := store.(*component.Memstore[Source, component.ID]) + require.True(t, ok) +} + +func TestService(t *testing.T) { + service := NewService(&component.MockStore[Source, component.ID]{ + OnCreate: func(entity Source, identifier component.ID) error { + require.Equal(t, MockID, string(identifier)) + require.Equal(t, MockEndpoint, entity.Endpoint()) + return nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + require.Equal(t, MockRegistryID, string(identifier)) + return ®istry.MockRegistry{}, nil + }, + }) + + err := service.Create(MockID, &Component{ + RegistryID: MockRegistryID, + Broker: MockHost, + Port: MockPort, + }) + require.NoError(t, err) +} + +func TestOptionalRegistry(t *testing.T) { + service := NewService(&component.MockStore[Source, component.ID]{ + OnCreate: func(entity Source, identifier component.ID) error { + brkr, ok := entity.(*Broker) + require.True(t, ok) + require.Equal(t, &observer.NoopObservable{}, brkr.Observable) + return nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, &component.NotFoundError{} + }, + }) + + err := service.Create(MockID, &Component{}) + require.NoError(t, err) +} + +func TestRegistryError(t *testing.T) { + service := NewService(&component.MockStore[Source, component.ID]{ + OnCreate: func(entity Source, identifier component.ID) error { + brkr, ok := entity.(*Broker) + require.True(t, ok) + require.Equal(t, &observer.NoopObservable{}, brkr.Observable) + return nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, &component.MockError{} + }, + }) + + err := service.Create(MockID, &Component{}) + require.Equal(t, &component.MockError{}, err) +} diff --git a/samples/krill/components/client/client.go b/samples/krill/components/client/client.go new file mode 100644 index 0000000..28766d0 --- /dev/null +++ b/samples/krill/components/client/client.go @@ -0,0 +1,356 @@ +// Package client contains all MQTT client interfaces and implementations. +// It defines several client implementations, including MQTT v3 and v5 compatible clients +// as well as mocking clients for testing. +package client + +import ( + "context" + "fmt" + "time" + + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/components/site" + "github.com/iot-for-all/device-simulation/lib/logger" + + mqtt "github.com/eclipse/paho.mqtt.golang" +) + +// PublisherSubscriber is the composite interface which represents the capabilities of a full featured client. +// These include publishing, subscribing and unsubscribing, and connecting and disconnecting from the broker. +type PublisherSubscriber interface { + Publisher + Subscriber + BrokerConnection + site.Site + GetName() string +} + +// Publisher is an interface whose implementation should include the observable functionality (see registry package), +// as well as the ability to publish a message on a given topic. +type Publisher interface { + Publish(topic string, qos byte, messagesRetained bool, data []byte) error + ConnectionNotifier + registry.Observable +} + +// Subscriber is an interface whose implementation should be able to subscribe and unsubscribe from particular topics. +// It also includes the connection notifier functionality. +type Subscriber interface { + Subscribe(topic string, qos byte, onReceived func([]byte)) error + Unsubscribe(topic string) error + ConnectionNotifier +} + +// ConnectionNotifier is an interface whose implementation should be able to close a channel upon a successful +// MQTT broker connection and close another channel upon a successful broker disconnection. +type ConnectionNotifier interface { + Connected() chan struct{} + Disconnected() chan struct{} +} + +// BrokerConnection is an interface whose implementation should be able to connect and disconnect from an MQTT broker. +type BrokerConnection interface { + Connect() error + Disconnect() error +} + +// Client implements the ConnectionNotifier interface and serves as base functionality which can be included via +// composition in PublisherSubscriber implementations. +type Client struct { + ctx context.Context + onDisconnect chan struct{} + onConnect chan struct{} + registry.Observable + broker registry.Observable + site.Site + Name string + Logger logger.Logger + Debug logger.Logger + Trace logger.Logger +} + +// New creates a new Client, given a context. +func New( + ctx context.Context, + mon registry.Observable, + broker registry.Observable, + ste site.Site, + options ...func(*Client), +) *Client { + cli := &Client{ + onConnect: make(chan struct{}), + onDisconnect: make(chan struct{}), + broker: broker, + Site: ste, + Observable: mon, + ctx: ctx, + Logger: &logger.NoopLogger{}, + } + + for _, option := range options { + option(cli) + } + + cli.Debug = cli.Logger.Level(logger.Debug) + cli.Trace = cli.Logger.Level(logger.Trace) + + return cli +} + +// Connected returns the onConnect channel. +func (client *Client) Connected() chan struct{} { + return client.onConnect +} + +// Disconnected returns the onDisconnect channel. +func (client *Client) Disconnected() chan struct{} { + return client.onDisconnect +} + +func (client *Client) GetName() string { + return client.Name +} + +// Observe will pass a float64 value to be observed by the client monitor and the broker monitor. +func (client *Client) Observe(value float64) { + client.Observable.Observe(value) + client.broker.Observe(value) + client.Site.Observe(value) +} + +// Clientv3 is a full PublisherSubscriber implementation which follows the MQTTv3 client protocol. +type Clientv3 struct { + conn mqtt.Client + Client +} + +// NewClientv3 creates a Clientv3, given a paho mqttv3 connection and an underlying client. +func NewClientv3( + conn mqtt.Client, + cli Client, +) *Clientv3 { + return &Clientv3{ + conn: conn, + Client: cli, + } +} + +// Connect establishes a connection with an MQTT v3 compatible broker. +// It will block until the connection has succeeded or failed, and return an error if failed. +// It will also close the onConnect channel upon completion. +func (client *Clientv3) Connect() error { + client.Debug.Printf("attempting new connection with broker") + + token := client.conn.Connect() + + select { + case <-client.ctx.Done(): + client.Debug.Printf("connection to broker was interrupted by context cancellation") + return nil + case <-token.Done(): + } + + err := token.Error() + if err != nil { + client.Logger.Level(logger.Error).With("error", err.Error()).Printf("an error occurred when connection to the broker") + return err + } + + client.Debug.Printf("connection succeeded") + + close(client.onConnect) + + return nil +} + +// Disconnect will disconnect from a connected MQTT broker. +// It will also close the onDisconnect channel upon completion. +func (client *Clientv3) Disconnect() error { + client.Debug.Printf("attempting to disconnect from broker") + client.conn.Disconnect(0) + close(client.onDisconnect) + return nil +} + +// Publish will publish a message on a given topic to a connected MQTT broker. +// It will block until the message publish has succeeded or failed, and return an error if failed. +func (client *Clientv3) Publish( + topic string, + qos byte, + messagesRetained bool, + data []byte, +) error { + + client.Trace.With("topic", topic).With("qos", fmt.Sprintf("%b", qos)).Printf("publishing new message") + + token := client.conn.Publish(topic, qos, messagesRetained, data) + + select { + case <-client.ctx.Done(): + client.Debug.With("topic", topic).With("qos", fmt.Sprintf("%b", qos)).Printf("message publish cancelled due to context cancellation") + return nil + case <-token.Done(): + return token.Error() + } +} + +// Subscribe will subscribe to a given topic on a connected MQTT broker. +// An onReceived function will be registered and called any time a message is received from said broker. +func (client *Clientv3) Subscribe( + topic string, + qos byte, + onReceived func([]byte), +) error { + client.Debug.With("topic", topic).With("qos", fmt.Sprintf("%b", qos)).Printf("attempting new subscription") + + token := client.conn.Subscribe( + topic, + qos, + func(_ mqtt.Client, m mqtt.Message) { + client.Trace.With("topic", topic).With("qos", fmt.Sprintf("%b", qos)).Printf("message received from broker") + onReceived(m.Payload()) + }, + ) + + select { + case <-client.ctx.Done(): + client.Debug.With("topic", topic).With("qos", fmt.Sprintf("%b", qos)).Printf("subscription cancelled due to context cancellation") + return nil + case <-token.Done(): + return token.Error() + } +} + +// Unsubscribe will unsubscribe from a given topic of a connected MQTT broker. +func (client *Clientv3) Unsubscribe(topic string) error { + client.Debug.With("topic", topic).Printf("attempting to unsubscribe") + + token := client.conn.Unsubscribe(topic) + + select { + case <-client.ctx.Done(): + return nil + case <-token.Done(): + return token.Error() + } +} + +// MockClient is a PublisherSubscriber implementation used for testing purposes. +// It has callbacks which can be configured in tests to mock out client behaviors. +type MockClient struct { + OnDisconnect chan struct{} + OnConnect chan struct{} + OnSubscribe func(topic string, qos byte, onReceived func([]byte)) error + OnUnsubscribe func(topic string) error + OnPublish func(topic string, qos byte, messagesRetained bool, data []byte) error + OnGetName func() string + OnRender func() string + registry.Observable +} + +func (client *MockClient) GetName() string { + return client.OnGetName() +} + +func (client *MockClient) Render() string { + return client.OnRender() +} + +// Subscribe calls the mock client's OnSubscribe function, passing along its provided parameters. +func (client *MockClient) Subscribe( + topic string, + qos byte, + onReceived func([]byte), +) error { + return client.OnSubscribe(topic, qos, onReceived) +} + +// Publish calls the mock client's OnPublish function, passing along its provided parameters. +func (client *MockClient) Publish( + topic string, + qos byte, + messagesRetained bool, + data []byte, +) error { + return client.OnPublish(topic, qos, messagesRetained, data) +} + +// Unsubscribe calls the mock client's OnUnsubscribe function, passing along its provided parameters. +func (client *MockClient) Unsubscribe(topic string) error { + return client.OnUnsubscribe(topic) +} + +// Connect closes the mock client's OnConnect channel. +func (client *MockClient) Connect() error { + close(client.OnConnect) + return nil +} + +// Disconnect closes the mock client's OnDisconnect channel. +func (client *MockClient) Disconnect() error { + close(client.OnDisconnect) + return nil +} + +// Connected returns the mock client's OnConnect channel. +func (client *MockClient) Connected() chan struct{} { + return client.OnConnect +} + +// Disconnected returns the mock client's OnDisconnect channel. +func (client *MockClient) Disconnected() chan struct{} { + return client.OnDisconnect +} + +type MockV3Conn struct { + mqtt.Client + OnConnect func() mqtt.Token + OnDisconnect func(quiesce uint) + OnPublish func(topic string, qos byte, retained bool, payload interface{}) mqtt.Token + OnSubscribe func(topic string, qos byte, callback mqtt.MessageHandler) mqtt.Token + OnUnsubscribe func(topics ...string) mqtt.Token +} + +func (mock *MockV3Conn) Connect() mqtt.Token { + return mock.OnConnect() +} + +func (mock *MockV3Conn) Disconnect(quiesce uint) { + mock.OnDisconnect(quiesce) +} + +func (mock *MockV3Conn) Publish(topic string, qos byte, retained bool, payload interface{}) mqtt.Token { + return mock.OnPublish(topic, qos, retained, payload) +} + +func (mock *MockV3Conn) Subscribe(topic string, qos byte, callback mqtt.MessageHandler) mqtt.Token { + return mock.OnSubscribe(topic, qos, callback) +} + +func (mock *MockV3Conn) Unsubscribe(topics ...string) mqtt.Token { + return mock.OnUnsubscribe(topics...) +} + +type MockToken struct { + mqtt.Token + OnWait func() bool + OnWaitTimeout func(time.Duration) bool + OnDone func() <-chan struct{} + OnError func() error +} + +func (mock *MockToken) Wait() bool { + return mock.OnWait() +} + +func (mock *MockToken) WaitTimeout(t time.Duration) bool { + return mock.OnWaitTimeout(t) +} + +func (mock *MockToken) Done() <-chan struct{} { + return mock.OnDone() +} + +func (mock *MockToken) Error() error { + return mock.OnError() +} \ No newline at end of file diff --git a/samples/krill/components/client/client_test.go b/samples/krill/components/client/client_test.go new file mode 100644 index 0000000..4ffef39 --- /dev/null +++ b/samples/krill/components/client/client_test.go @@ -0,0 +1,533 @@ +package client + +import ( + "context" + "net" + "testing" + + mqttv5 "github.com/eclipse/paho.golang/paho" + mqtt "github.com/eclipse/paho.mqtt.golang" + "github.com/iot-for-all/device-simulation/components/site" + "github.com/iot-for-all/device-simulation/lib/errors" + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +var ( + exampleTopic = "example" +) + +func TestMockClient(t *testing.T) { + + client := &MockClient{ + OnDisconnect: make(chan struct{}), + OnConnect: make(chan struct{}), + OnSubscribe: func(topic string, qos byte, onReceived func([]byte)) error { + require.Equal(t, exampleTopic, topic) + return nil + }, OnUnsubscribe: func(topic string) error { + require.Equal(t, exampleTopic, topic) + return nil + }, OnPublish: func(topic string, qos byte, messagesRetained bool, data []byte) error { + require.Equal(t, exampleTopic, topic) + return nil + }, + } + + go func() { + require.NoError(t, client.Connect()) + }() + go func() { + require.NoError(t, client.Disconnect()) + }() + + <-client.Connected() + <-client.Disconnected() + + require.NoError(t, client.Publish(exampleTopic, 0, false, nil)) + require.NoError(t, client.Subscribe(exampleTopic, 0, func([]byte) {})) + require.NoError(t, client.Unsubscribe(exampleTopic)) +} + +type MockMQTTToken struct { + mqtt.Token + done chan struct{} + err error +} + +func (token *MockMQTTToken) Done() <-chan struct{} { + return token.done +} + +func (token *MockMQTTToken) Error() error { + return token.err +} + +type MockObserver struct { + onObserve func(float64) +} + +func (observer *MockObserver) Observe(value float64) { + observer.onObserve(value) +} + +type MockMessageHandler struct { + OnPayload func() []byte + mqtt.Message +} + +func (handler *MockMessageHandler) Payload() []byte { + return handler.OnPayload() +} + +func TestClientv3NoErrorsNoCancellations(t *testing.T) { + + ctx := context.Background() + mon := &MockObserver{} + broker := &MockObserver{} + onConnect := make(chan struct{}) + onPublish := make(chan struct{}) + onSub := make(chan struct{}) + onUnsub := make(chan struct{}) + sendSubscription := make(chan struct{}) + client := NewClientv3(&MockV3Conn{ + OnConnect: func() mqtt.Token { + return &MockMQTTToken{ + done: onConnect, + err: nil, + } + }, OnDisconnect: func(quiesce uint) { + + }, OnPublish: func(topic string, qos byte, retained bool, payload interface{}) mqtt.Token { + require.Equal(t, exampleTopic, topic) + return &MockMQTTToken{ + done: onPublish, + err: nil, + } + }, OnSubscribe: func(topic string, qos byte, callback mqtt.MessageHandler) mqtt.Token { + go func() { + <-sendSubscription + callback(nil, &MockMessageHandler{ + OnPayload: func() []byte { + return nil + }, + }) + }() + require.Equal(t, exampleTopic, topic) + return &MockMQTTToken{ + done: onSub, + err: nil, + } + }, OnUnsubscribe: func(topics ...string) mqtt.Token { + require.Equal(t, exampleTopic, topics[0]) + return &MockMQTTToken{ + done: onUnsub, + err: nil, + } + }, + }, *New(ctx, mon, broker, &site.MockSite{ + OnRender: func() string { + return "" + }, + })) + + go func() { + close(onConnect) + }() + + go func() { + close(onPublish) + }() + + go func() { + close(onSub) + }() + + go func() { + close(onUnsub) + }() + + require.NoError(t, client.Connect()) + + <-client.Connected() + + require.NoError(t, client.Subscribe(exampleTopic, 0, func([]byte) {})) + + subscriptionReceived := make(chan struct{}) + + require.NoError(t, client.Subscribe(exampleTopic, 0, func([]byte) { + close(subscriptionReceived) + })) + + require.NoError(t, client.Publish(exampleTopic, 0, false, nil)) + + go func() { + require.NoError(t, client.Disconnect()) + }() + + <-client.Disconnected() + + go func() { + close(sendSubscription) + }() + + <-subscriptionReceived +} + +func TestClientv3WithContextCancellations(t *testing.T) { + + ctx, cancel := context.WithCancel(context.Background()) + mon := &MockObserver{} + broker := &MockObserver{} + onConnect := make(chan struct{}) + onPublish := make(chan struct{}) + onSub := make(chan struct{}) + onUnsub := make(chan struct{}) + client := NewClientv3(&MockV3Conn{ + OnConnect: func() mqtt.Token { + return &MockMQTTToken{ + done: onConnect, + err: errors.Mock{}, + } + }, OnDisconnect: func(quiesce uint) { + + }, OnPublish: func(topic string, qos byte, retained bool, payload interface{}) mqtt.Token { + require.Equal(t, exampleTopic, topic) + return &MockMQTTToken{ + done: onPublish, + err: errors.Mock{}, + } + }, OnSubscribe: func(topic string, qos byte, callback mqtt.MessageHandler) mqtt.Token { + require.Equal(t, exampleTopic, topic) + return &MockMQTTToken{ + done: onSub, + err: errors.Mock{}, + } + }, OnUnsubscribe: func(topics ...string) mqtt.Token { + require.Equal(t, exampleTopic, topics[0]) + return &MockMQTTToken{ + done: onUnsub, + err: errors.Mock{}, + } + }, + }, *New(ctx, mon, broker, &site.MockSite{ + OnRender: func() string { + return "" + }, + })) + + go func() { + cancel() + }() + + require.NoError(t, client.Connect()) + + notConnected := make(chan struct{}) + + select { + case <-client.Connected(): + default: + close(notConnected) + } + + <-notConnected + + require.NoError(t, client.Subscribe(exampleTopic, 0, func([]byte) { + })) + + require.NoError(t, client.Unsubscribe(exampleTopic)) + + require.NoError(t, client.Publish(exampleTopic, 0, false, nil)) + + go func() { + require.NoError(t, client.Disconnect()) + }() + + notDisconnected := make(chan struct{}) + + select { + case <-client.Connected(): + default: + close(notDisconnected) + } + + <-notDisconnected +} + +func TestClientv3WithMockObserver(t *testing.T) { + observed := 101.101 + mon := &MockObserver{ + onObserve: func(f float64) { + require.Equal(t, observed, f) + }, + } + broker := &MockObserver{ + onObserve: func(f float64) { + require.Equal(t, observed, f) + }, + } + site := &site.MockSite{ + Observable: &MockObserver{ + onObserve: func(f float64) { + require.Equal(t, observed, f) + }, + }, + OnRender: func() string { + return "" + }, + } + client := NewClientv3(nil, *New(context.Background(), mon, broker, site)) + client.Observe(observed) +} + +func TestClientv3WithConnectionTokenError(t *testing.T) { + mon := &MockObserver{} + broker := &MockObserver{} + onConnect := make(chan struct{}) + client := NewClientv3(&MockV3Conn{ + OnConnect: func() mqtt.Token { + return &MockMQTTToken{ + done: onConnect, + err: errors.Mock{}, + } + }, + }, *New(context.Background(), mon, broker, &site.MockSite{ + OnRender: func() string { + return "" + }, + })) + go func() { + close(onConnect) + }() + require.Equal(t, errors.Mock{}, client.Connect()) + + notConnected := make(chan struct{}) + + select { + case <-client.Connected(): + default: + close(notConnected) + } + + <-notConnected +} + +func TestClientv3WithUnsubscribeTokenError(t *testing.T) { + mon := &MockObserver{} + broker := &MockObserver{} + onUnsub := make(chan struct{}) + client := NewClientv3(&MockV3Conn{ + OnUnsubscribe: func(topics ...string) mqtt.Token { + return &MockMQTTToken{ + done: onUnsub, + err: errors.Mock{}, + } + }, + }, *New(context.Background(), mon, broker, &site.MockSite{ + OnRender: func() string { + return "" + }, + })) + go func() { + close(onUnsub) + }() + require.Equal(t, errors.Mock{}, client.Unsubscribe("")) +} + +type MockConn struct { + net.Conn +} + +func TestClientv5ConnectAndDisconnect(t *testing.T) { + ctx := context.Background() + mon := &MockObserver{} + broker := &MockObserver{} + + client := NewClientv5(&MockV5Wrapper{ + OnConnect: func(ctx context.Context, cp *mqttv5.Connect) (*mqttv5.Connack, error) { + return nil, nil + }, + OnDisconnect: func(d *mqttv5.Disconnect) error { + return nil + }, + }, *New(ctx, mon, broker, &site.MockSite{ + OnRender: func() string { + return "" + }, + })) + + require.NoError(t, client.Connect()) + + <-client.Connected() + + require.NoError(t, client.Disconnect()) + + <-client.Disconnected() +} + +func TestClientv5ConnectError(t *testing.T) { + ctx := context.Background() + mon := &MockObserver{} + broker := &MockObserver{} + + client := NewClientv5(&MockV5Wrapper{ + OnConnect: func(ctx context.Context, cp *mqttv5.Connect) (*mqttv5.Connack, error) { + return nil, errors.Mock{} + }, + }, *New(ctx, mon, broker, &site.MockSite{ + OnRender: func() string { + return "" + }, + })) + + require.Equal(t, errors.Mock{}, client.Connect()) +} + +func TestClientv5DisconnectError(t *testing.T) { + ctx := context.Background() + mon := &MockObserver{} + broker := &MockObserver{} + + client := NewClientv5(&MockV5Wrapper{ + OnDisconnect: func(d *mqttv5.Disconnect) error { + return errors.Mock{} + }, + }, *New(ctx, mon, broker, &site.MockSite{ + OnRender: func() string { + return "" + }, + })) + + require.Equal(t, errors.Mock{}, client.Disconnect()) +} + +func TestClientv5Publish(t *testing.T) { + ctx := context.Background() + mon := &MockObserver{} + broker := &MockObserver{} + + client := NewClientv5(&MockV5Wrapper{ + OnPublish: func(ctx context.Context, p *mqttv5.Publish) (*mqttv5.PublishResponse, error) { + return nil, errors.Mock{} + }, + }, *New(ctx, mon, broker, &site.MockSite{ + OnRender: func() string { + return "" + }, + })) + + require.Equal(t, errors.Mock{}, client.Publish("", 0, false, nil)) +} + +func TestClientv5Subscribe(t *testing.T) { + ctx := context.Background() + mon := &MockObserver{} + broker := &MockObserver{} + + client := NewClientv5(&MockV5Wrapper{ + OnSubscribe: func(ctx context.Context, s *mqttv5.Subscribe) (*mqttv5.Suback, error) { + return nil, nil + }, OnRegisterHandler: func(s string, mh mqttv5.MessageHandler) {}, + }, *New(ctx, mon, broker, &site.MockSite{ + OnRender: func() string { + return "" + }, + })) + + require.NoError(t, client.Subscribe("", 0, func([]byte) {})) +} + +func TestClientv5SubscribeError(t *testing.T) { + ctx := context.Background() + mon := &MockObserver{} + broker := &MockObserver{} + + client := NewClientv5(&MockV5Wrapper{ + OnSubscribe: func(ctx context.Context, s *mqttv5.Subscribe) (*mqttv5.Suback, error) { + return nil, errors.Mock{} + }, + }, *New(ctx, mon, broker, &site.MockSite{ + OnRender: func() string { + return "" + }, + })) + + require.Equal(t, errors.Mock{}, client.Subscribe("", 0, func([]byte) {})) +} + +func TestClientv5Unsubscribe(t *testing.T) { + ctx := context.Background() + mon := &MockObserver{} + broker := &MockObserver{} + + client := NewClientv5(&MockV5Wrapper{ + OnUnsubscribe: func(ctx context.Context, u *mqttv5.Unsubscribe) (*mqttv5.Unsuback, error) { + return nil, nil + }, + OnUnregisterHandler: func(string) {}, + }, *New(ctx, mon, broker, &site.MockSite{ + OnRender: func() string { + return "" + }, + })) + + require.NoError(t, client.Unsubscribe("")) +} + +func TestClientv5UnsubscribeError(t *testing.T) { + ctx := context.Background() + mon := &MockObserver{} + broker := &MockObserver{} + + client := NewClientv5(&MockV5Wrapper{ + OnUnsubscribe: func(ctx context.Context, u *mqttv5.Unsubscribe) (*mqttv5.Unsuback, error) { + return nil, errors.Mock{} + }, OnUnregisterHandler: func(s string) {}, + }, *New(ctx, mon, broker, &site.MockSite{ + OnRender: func() string { + return "" + }, + })) + + require.Equal(t, errors.Mock{}, client.Unsubscribe("")) +} + +func TestMockClientv5Wrapper(t *testing.T) { + client := &MockV5Wrapper{ + OnConnect: func(ctx context.Context, cp *mqttv5.Connect) (*mqttv5.Connack, error) { + return nil, nil + }, + OnDisconnect: func(d *mqttv5.Disconnect) error { + return nil + }, + OnPublish: func(ctx context.Context, p *mqttv5.Publish) (*mqttv5.PublishResponse, error) { + return nil, nil + }, + OnSubscribe: func(ctx context.Context, s *mqttv5.Subscribe) (*mqttv5.Suback, error) { + return nil, nil + }, + OnUnsubscribe: func(ctx context.Context, u *mqttv5.Unsubscribe) (*mqttv5.Unsuback, error) { + return nil, nil + }, + OnRegisterHandler: func(string, mqttv5.MessageHandler) { + }, + OnUnregisterHandler: func(string) { + }, + } + + _, err := client.Connect(context.TODO(), nil) + require.NoError(t, err) + _, err = client.Publish(context.TODO(), nil) + require.NoError(t, err) + _, err = client.Subscribe(context.TODO(), nil) + require.NoError(t, err) + _, err = client.Unsubscribe(context.TODO(), nil) + require.NoError(t, err) + require.NoError(t, client.Disconnect(nil)) + client.RegisterHandler("", nil) + client.UnregisterHandler("") + +} \ No newline at end of file diff --git a/samples/krill/components/client/clientv5.go b/samples/krill/components/client/clientv5.go new file mode 100644 index 0000000..6173fbd --- /dev/null +++ b/samples/krill/components/client/clientv5.go @@ -0,0 +1,261 @@ +package client + +import ( + "context" + "fmt" + + "github.com/eclipse/paho.golang/paho" + "github.com/iot-for-all/device-simulation/lib/logger" +) + +// Clientv5 is a full PublisherSubscriber implementation which follows the MQTTv5 client protocol. +type Clientv5 struct { + conn V5Conn + Client +} + +// NewClientv5 creates a Clientv5, given a V5Conn wrapper (wrapper around paho v5 connection) and an underlying client. +func NewClientv5( + conn V5Conn, + cli Client, +) *Clientv5 { + return &Clientv5{ + conn: conn, + Client: cli, + } +} + +// Connect establishes a connection with an MQTT v5 compatible broker. +// It will also close the onConnect channel if the connection succeeds. +func (client *Clientv5) Connect() error { + client.Debug.Printf("attempting new connection with broker") + + _, err := client.conn.Connect(client.ctx, &paho.Connect{ + KeepAlive: 5, + CleanStart: true, + }) + if err != nil { + client.Logger.Level(logger.Error).With("error", err.Error()).Printf("an error occurred when connecting to the broker") + return err + } + close(client.onConnect) + return err +} + +// Disconnect will disconnect from a connected MQTT broker. +// It will also close the onDisconnect channel upon completion. +func (client *Clientv5) Disconnect() error { + client.Debug.Printf("attempting to disconnect from broker") + err := client.conn.Disconnect(&paho.Disconnect{}) + if err != nil { + client.Logger.Level(logger.Error).With("error", err.Error()).Printf("an error occurred when disconnecting from the broker") + return err + } + close(client.onDisconnect) + return nil +} + +// Publish will publish a message on a given topic to a connected MQTT broker. +// It will block until the message publish has succeeded or failed, and return an error if failed. +func (client *Clientv5) Publish( + topic string, + qos byte, + messagesRetained bool, + data []byte, +) error { + client.Trace.With("topic", topic).With("qos", fmt.Sprintf("%b", qos)).Printf("publishing new message") + _, err := client.conn.Publish(client.ctx, &paho.Publish{ + QoS: qos, + Retain: messagesRetained, + Topic: topic, + Payload: data, + }) + if err != nil { + client.Logger.Level(logger.Error).With("error", err.Error()).With("topic", topic).With("qos", fmt.Sprintf("%b", qos)).Printf("message publish failed") + return err + } + + return nil +} + +// Subscribe will subscribe to a given topic on a connected MQTT broker. +// An onReceived function will be registered and called any time a message is received from said broker. +func (client *Clientv5) Subscribe( + topic string, + qos byte, + onReceived func([]byte), +) error { + client.Debug.With("topic", topic).With("qos", fmt.Sprintf("%b", qos)).Printf("attempting new subscription") + + _, err := client.conn.Subscribe(client.ctx, &paho.Subscribe{ + Subscriptions: map[string]paho.SubscribeOptions{ + topic: { + QoS: qos, + }, + }, + }) + if err != nil { + client.Logger.Level(logger.Error).With("error", err.Error()).With("topic", topic).With("qos", fmt.Sprintf("%b", qos)).Printf("failed to subscribe to the broker") + return err + } + + client.conn.RegisterHandler(topic, func(p *paho.Publish) { + client.Trace.With("topic", topic).With("qos", fmt.Sprintf("%b", qos)).Printf("message received from broker") + onReceived(p.Payload) + }) + + return nil +} + +// Unsubscribe will unsubscribe from a given topic of a connected MQTT broker. +func (client *Clientv5) Unsubscribe(topic string) error { + client.Debug.With("topic", topic).Printf("attempting to unsubscribe") + + client.conn.UnregisterHandler(topic) + + _, err := client.conn.Unsubscribe(client.ctx, &paho.Unsubscribe{ + Topics: []string{topic}, + }) + if err != nil { + client.Logger.Level(logger.Error).With("error", err.Error()).With("topic", topic).Printf("failed to unsubscribe from the broker") + return err + } + + return nil +} + +// V5Conn is an interface whose implementation should be a wrapper around the paho v5 client functionality. +// The purpose of the interface and wrapper is for testing/mocking purposes, and the paho v5 client is difficult +// to mock due to the underlying TCP connection it depends on. +type V5Conn interface { + Connect(ctx context.Context, cp *paho.Connect) (*paho.Connack, error) + Disconnect(d *paho.Disconnect) error + Publish(ctx context.Context, p *paho.Publish) (*paho.PublishResponse, error) + Subscribe(ctx context.Context, s *paho.Subscribe) (*paho.Suback, error) + Unsubscribe( + ctx context.Context, + u *paho.Unsubscribe, + ) (*paho.Unsuback, error) + RegisterHandler(string, paho.MessageHandler) + UnregisterHandler(string) +} + +// V5Wrapper is an implementation of V5Conn which wraps the functionality of the paho v5 client. +type V5Wrapper struct { + conn *paho.Client +} + +// NewV5Wrapper creates a new V5Wrapper given a paho v5 client. +func NewV5Wrapper(conn *paho.Client) V5Conn { + return &V5Wrapper{ + conn: conn, + } +} + +// Connect sets the clientID in the paho connect packet cp equal to the ID of the paho client. +// It then calls the paho client's connect function, passing along its parameters. +func (wrapper *V5Wrapper) Connect( + ctx context.Context, + cp *paho.Connect, +) (*paho.Connack, error) { + cp.ClientID = wrapper.conn.ClientID + return wrapper.conn.Connect(ctx, cp) +} + +// Disconnect calls the paho client's disconnect function, passing along its disconnect packet parameter. +func (wrapper *V5Wrapper) Disconnect(d *paho.Disconnect) error { + return wrapper.conn.Disconnect(d) +} + +// Publish calls the paho client's publish function, passing through its context and publish packet parameters. +func (wrapper *V5Wrapper) Publish( + ctx context.Context, + p *paho.Publish, +) (*paho.PublishResponse, error) { + return wrapper.conn.Publish(ctx, p) +} + +// Subscribe calls the paho client's subscribe function, passing through its context and subscribe packet parameters. +func (wrapper *V5Wrapper) Subscribe( + ctx context.Context, + s *paho.Subscribe, +) (*paho.Suback, error) { + return wrapper.conn.Subscribe(ctx, s) +} + +// Unsubscribe calls the paho client's unsubscribe function, passing through its context and unsubscribe packet parameters. +func (wrapper *V5Wrapper) Unsubscribe( + ctx context.Context, + u *paho.Unsubscribe, +) (*paho.Unsuback, error) { + return wrapper.conn.Unsubscribe(ctx, u) +} + +// RegisterHandler calls the paho client's register handler function, passing through a provided topic, and a message handler. +func (wrapper *V5Wrapper) RegisterHandler(topic string, p paho.MessageHandler) { + wrapper.conn.Router.RegisterHandler(topic, p) +} + +// UnregisterHandler calls the paho client's unregister handler function, passing through a provided topic. +func (wrapper *V5Wrapper) UnregisterHandler(topic string) { + wrapper.conn.Router.UnregisterHandler(topic) +} + +// MockV5Wrapper is a mocking struct designed for testing. +// It implements the V5Conn interface. +type MockV5Wrapper struct { + OnConnect func(ctx context.Context, cp *paho.Connect) (*paho.Connack, error) + OnDisconnect func(d *paho.Disconnect) error + OnPublish func(ctx context.Context, p *paho.Publish) (*paho.PublishResponse, error) + OnSubscribe func(ctx context.Context, s *paho.Subscribe) (*paho.Suback, error) + OnUnsubscribe func(ctx context.Context, u *paho.Unsubscribe) (*paho.Unsuback, error) + OnRegisterHandler func(string, paho.MessageHandler) + OnUnregisterHandler func(string) +} + +// Connect calls the OnConnect function, passing through its parameters. +func (wrapper *MockV5Wrapper) Connect( + ctx context.Context, + cp *paho.Connect, +) (*paho.Connack, error) { + return wrapper.OnConnect(ctx, cp) +} + +// Connect calls the OnDisconnect function, passing through its parameters. +func (wrapper *MockV5Wrapper) Disconnect(d *paho.Disconnect) error { + return wrapper.OnDisconnect(d) +} + +// Publish calls the OnPublish function, passing through its parameters. +func (wrapper *MockV5Wrapper) Publish( + ctx context.Context, + p *paho.Publish, +) (*paho.PublishResponse, error) { + return wrapper.OnPublish(ctx, p) +} + +// Subscribe calls the OnSubscribe function, passing through its parameters. +func (wrapper *MockV5Wrapper) Subscribe( + ctx context.Context, + s *paho.Subscribe, +) (*paho.Suback, error) { + return wrapper.OnSubscribe(ctx, s) +} + +// Unsubscribe calls the OnUnsubscribe function, passing through its parameters. +func (wrapper *MockV5Wrapper) Unsubscribe( + ctx context.Context, + u *paho.Unsubscribe, +) (*paho.Unsuback, error) { + return wrapper.OnUnsubscribe(ctx, u) +} + +// RegisterHandler calls the OnRegisterHandler function, passing through its parameters. +func (wrapper *MockV5Wrapper) RegisterHandler(s string, p paho.MessageHandler) { + wrapper.OnRegisterHandler(s, p) +} + +// UnregisterHandler calls the OnUnregisterHandler function, passing through its parameters. +func (wrapper *MockV5Wrapper) UnregisterHandler(s string) { + wrapper.OnUnregisterHandler(s) +} diff --git a/samples/krill/components/client/errors.go b/samples/krill/components/client/errors.go new file mode 100644 index 0000000..bbd8a16 --- /dev/null +++ b/samples/krill/components/client/errors.go @@ -0,0 +1,32 @@ +package client + +import ( + "fmt" + + "github.com/iot-for-all/device-simulation/lib/errors" +) + +type BrokerConnectionError struct { + errors.BadRequest + id string + endpoint string + err error +} + +func (err *BrokerConnectionError) Error() string { + return fmt.Sprintf( + "mqtt client with id=%s could not connect to MQTT broker at endpoint %s: %q", + err.id, + err.endpoint, + err.err.Error(), + ) +} + +type UnknownClientTypeError struct { + errors.BadRequest + name string +} + +func (err *UnknownClientTypeError) Error() string { + return fmt.Sprintf("no such %s type for mqtt client component", err.name) +} \ No newline at end of file diff --git a/samples/krill/components/client/service.go b/samples/krill/components/client/service.go new file mode 100644 index 0000000..3e0aa59 --- /dev/null +++ b/samples/krill/components/client/service.go @@ -0,0 +1,146 @@ +package client + +import ( + "context" + + "github.com/iot-for-all/device-simulation/components/broker" + "github.com/iot-for-all/device-simulation/components/observer" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/components/site" + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/iot-for-all/device-simulation/lib/dialer" + "github.com/iot-for-all/device-simulation/lib/logger" + + mqttv5 "github.com/eclipse/paho.golang/paho" + mqttv3 "github.com/eclipse/paho.mqtt.golang" +) + +type Store component.Store[PublisherSubscriber, component.ID] + +type Type string + +const ( + V3 Type = "v3" + V5 Type = "v5" +) + +type Component struct { + RegistryID component.ID + BrokerID component.ID + SiteID component.ID + Name string + Password string + Username string + ConnectionRetries int + Type Type +} + +type Service struct { + Store + registryStore registry.Store + brokerStore broker.Store + siteStore site.Store + Dialer dialer.Dialer + Logger logger.Logger + CreateV5Conn func(conn *mqttv5.Client) V5Conn + CreateV3Conn func(o *mqttv3.ClientOptions) mqttv3.Client + ctx context.Context +} + +func NewStore() Store { + return component.New[PublisherSubscriber, component.ID]() +} + +func NewService( + ctx context.Context, + store Store, + registryStore registry.Store, + brokerStore broker.Store, + siteStore site.Store, + options ...func(*Service), +) *Service { + service := &Service{ + Store: store, + registryStore: registryStore, + brokerStore: brokerStore, + siteStore: siteStore, + Dialer: dialer.New(), + Logger: &logger.NoopLogger{}, + CreateV5Conn: NewV5Wrapper, + CreateV3Conn: mqttv3.NewClient, + ctx: ctx, + } + + for _, option := range options { + option(service) + } + + return service +} + +func (service *Service) Create(id component.ID, c *Component) error { + var reg registry.Observable + reg, err := service.registryStore.Get(c.RegistryID) + if err != nil { + _, ok := err.(*component.NotFoundError) + if !ok { + return err + } + reg = &observer.NoopObservable{} + } + + brkr, err := service.brokerStore.Get(c.BrokerID) + if err != nil { + return err + } + + ste, err := service.siteStore.Get(c.SiteID) + if err != nil { + return err + } + + base := New(service.ctx, reg, brkr, ste, func(cli *Client) { + cli.Name = c.Name + cli.Logger = service.Logger.With("name", c.Name).With("site", ste.Render()).With("mqtt_version", string(c.Type)).With("broker_endpoint", brkr.Endpoint()) + }) + var cli PublisherSubscriber + switch c.Type { + case V5: + conn, err := service.Dialer.Dial("tcp", brkr.Endpoint()) + if err != nil { + return &BrokerConnectionError{ + id: string(id), + endpoint: brkr.Endpoint(), + err: err, + } + } + + pcli := mqttv5.NewClient(mqttv5.ClientConfig{ + Router: mqttv5.NewStandardRouter(), + Conn: conn, + ClientID: c.Name, + }) + + cli = NewClientv5(service.CreateV5Conn(pcli), *base) + case V3: + opt := mqttv3.NewClientOptions() + opt.AddBroker(brkr.Endpoint()) + opt.SetClientID(c.Name) + opt.SetUsername(c.Username) + opt.SetPassword(c.Password) + opt.SetCleanSession(true) + + cli = NewClientv3(service.CreateV3Conn(opt), *base) + default: + return &UnknownClientTypeError{ + name: string(c.Type), + } + } + + err = cli.Connect() + if err != nil { + return err + } + + return service.Store.Create(cli, id) +} diff --git a/samples/krill/components/client/service_test.go b/samples/krill/components/client/service_test.go new file mode 100644 index 0000000..9786eb4 --- /dev/null +++ b/samples/krill/components/client/service_test.go @@ -0,0 +1,397 @@ +package client + +import ( + "context" + "net" + "testing" + + "github.com/iot-for-all/device-simulation/components/broker" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/components/site" + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/iot-for-all/device-simulation/lib/dialer" + "github.com/stretchr/testify/require" + + mqttv5 "github.com/eclipse/paho.golang/paho" + mqttv3 "github.com/eclipse/paho.mqtt.golang" +) + +const ( + MockID = "MockID" + MockRegistryID = "MockRegistryID" + MockBrokerID = "MockBrokerID" + MockSiteID = "MockSiteID" + MockEndpoint = "MockEndpoint" + MockSite = "MockSite" + MockName = "MockName" + MockPassword = "MockPassword" + MockUsername = "MockUsername" + MockType = "MockType" + MockError = "MockError" +) + +func TestStore(t *testing.T) { + store := NewStore() + _, ok := store.(*component.Memstore[PublisherSubscriber, component.ID]) + require.True(t, ok) +} + +func TestServiceClientV5(t *testing.T) { + + ctx := context.Background() + + service := NewService(ctx, &component.MockStore[PublisherSubscriber, component.ID]{ + OnCreate: func(entity PublisherSubscriber, identifier component.ID) error { + require.Equal(t, MockID, string(identifier)) + return nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + require.Equal(t, MockRegistryID, string(identifier)) + return ®istry.MockRegistry{}, nil + }, + }, &component.MockStore[broker.Source, component.ID]{ + OnGet: func(identifier component.ID) (broker.Source, error) { + require.Equal(t, MockBrokerID, string(identifier)) + return &broker.MockBroker{ + OnEndpoint: func() string { + return MockEndpoint + }, + }, nil + }, + }, &component.MockStore[site.Site, component.ID]{ + OnGet: func(identifier component.ID) (site.Site, error) { + require.Equal(t, MockSiteID, string(identifier)) + return &site.MockSite{ + OnRender: func() string { + return MockSite + }, + }, nil + }, + }, func(s *Service) { + s.Dialer = &dialer.MockDialer{ + OnDial: func(network, address string) (net.Conn, error) { + return &dialer.NoopConn{}, nil + }, + } + s.CreateV5Conn = func(conn *mqttv5.Client) V5Conn { + return &MockV5Wrapper{ + OnConnect: func(ctx context.Context, cp *mqttv5.Connect) (*mqttv5.Connack, error) { + return nil, nil + }, + } + } + }) + + err := service.Create(MockID, &Component{ + RegistryID: MockRegistryID, + BrokerID: MockBrokerID, + SiteID: MockSiteID, + Type: V5, + }) + require.NoError(t, err) +} + +func TestServiceClientV3(t *testing.T) { + + ctx := context.Background() + + service := NewService(ctx, &component.MockStore[PublisherSubscriber, component.ID]{ + OnCreate: func(entity PublisherSubscriber, identifier component.ID) error { + require.Equal(t, MockID, string(identifier)) + return nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + require.Equal(t, MockRegistryID, string(identifier)) + return ®istry.MockRegistry{}, nil + }, + }, &component.MockStore[broker.Source, component.ID]{ + OnGet: func(identifier component.ID) (broker.Source, error) { + require.Equal(t, MockBrokerID, string(identifier)) + return &broker.MockBroker{ + OnEndpoint: func() string { + return MockEndpoint + }, + }, nil + }, + }, &component.MockStore[site.Site, component.ID]{ + OnGet: func(identifier component.ID) (site.Site, error) { + require.Equal(t, MockSiteID, string(identifier)) + return &site.MockSite{ + OnRender: func() string { + return MockSite + }, + }, nil + }, + }, func(s *Service) { + s.CreateV3Conn = func(o *mqttv3.ClientOptions) mqttv3.Client { + require.Equal(t, MockEndpoint, o.Servers[0].Host) + require.Equal(t, MockName, o.ClientID) + require.Equal(t, MockPassword, o.Password) + require.Equal(t, MockUsername, o.Username) + require.True(t, o.CleanSession) + return &MockV3Conn{ + OnConnect: func() mqttv3.Token { + return &MockToken{ + OnDone: func() <-chan struct{} { + c := make(chan struct{}) + close(c) + return c + }, OnError: func() error { + return nil + }, + } + }, + } + } + }) + + err := service.Create(MockID, &Component{ + RegistryID: MockRegistryID, + BrokerID: MockBrokerID, + SiteID: MockSiteID, + Name: MockName, + Password: MockPassword, + Username: MockUsername, + ConnectionRetries: 0, + Type: V3, + }) + require.NoError(t, err) +} + +func TestServiceInvalidClientType(t *testing.T) { + + ctx := context.Background() + + service := NewService(ctx, &component.MockStore[PublisherSubscriber, component.ID]{ + OnCreate: func(entity PublisherSubscriber, identifier component.ID) error { + return nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return ®istry.MockRegistry{}, nil + }, + }, &component.MockStore[broker.Source, component.ID]{ + OnGet: func(identifier component.ID) (broker.Source, error) { + return &broker.MockBroker{ + OnEndpoint: func() string { + return MockEndpoint + }, + }, nil + }, + }, &component.MockStore[site.Site, component.ID]{ + OnGet: func(identifier component.ID) (site.Site, error) { + return &site.MockSite{ + OnRender: func() string { + return MockSite + }, + }, nil + }, + }) + + err := service.Create(MockID, &Component{ + RegistryID: MockRegistryID, + BrokerID: MockBrokerID, + SiteID: MockSiteID, + Name: MockName, + Password: MockPassword, + Username: MockUsername, + ConnectionRetries: 0, + Type: MockType, + }) + require.Equal(t, &UnknownClientTypeError{ + name: MockType, + }, err) +} + +func TestServiceClientV3ConnectionError(t *testing.T) { + + ctx := context.Background() + + service := NewService(ctx, &component.MockStore[PublisherSubscriber, component.ID]{ + OnCreate: func(entity PublisherSubscriber, identifier component.ID) error { + return nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return ®istry.MockRegistry{}, nil + }, + }, &component.MockStore[broker.Source, component.ID]{ + OnGet: func(identifier component.ID) (broker.Source, error) { + return &broker.MockBroker{ + OnEndpoint: func() string { + return MockEndpoint + }, + }, nil + }, + }, &component.MockStore[site.Site, component.ID]{ + OnGet: func(identifier component.ID) (site.Site, error) { + return &site.MockSite{ + OnRender: func() string { + return MockSite + }, + }, nil + }, + }, func(s *Service) { + s.CreateV3Conn = func(o *mqttv3.ClientOptions) mqttv3.Client { + return &MockV3Conn{ + OnConnect: func() mqttv3.Token { + return &MockToken{ + OnDone: func() <-chan struct{} { + c := make(chan struct{}) + close(c) + return c + }, OnError: func() error { + return &component.MockError{ + OnError: func() string { + return "" + }, + } + }, + } + }, + } + } + }) + + err := service.Create(MockID, &Component{ + Type: V3, + }) + _, ok := err.(*component.MockError) + require.True(t, ok) +} + +func TestServiceClientV5DialError(t *testing.T) { + + ctx := context.Background() + + service := NewService(ctx, &component.MockStore[PublisherSubscriber, component.ID]{ + OnCreate: func(entity PublisherSubscriber, identifier component.ID) error { + return nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return ®istry.MockRegistry{}, nil + }, + }, &component.MockStore[broker.Source, component.ID]{ + OnGet: func(identifier component.ID) (broker.Source, error) { + return &broker.MockBroker{ + OnEndpoint: func() string { + return MockEndpoint + }, + }, nil + }, + }, &component.MockStore[site.Site, component.ID]{ + OnGet: func(identifier component.ID) (site.Site, error) { + return &site.MockSite{ + OnRender: func() string { + return MockSite + }, + }, nil + }, + }, func(s *Service) { + s.Dialer = &dialer.MockDialer{ + OnDial: func(network, address string) (net.Conn, error) { + return nil, &component.MockError{} + }, + } + }) + + err := service.Create(MockID, &Component{ + Type: V5, + }) + require.Equal(t, &BrokerConnectionError{ + id: MockID, + err: &component.MockError{}, + endpoint: MockEndpoint, + }, err) +} + +func TestServiceRegistryStoreGetError(t *testing.T) { + + ctx := context.Background() + + service := NewService(ctx, nil, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, &component.MockError{} + }, + }, nil, nil) + + err := service.Create(MockID, &Component{ + Type: V5, + }) + require.Equal(t, &component.MockError{}, err) +} + +func TestServiceBrokerError(t *testing.T) { + + ctx := context.Background() + + service := NewService(ctx, nil, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, nil + }, + }, &component.MockStore[broker.Source, component.ID]{ + OnGet: func(identifier component.ID) (broker.Source, error) { + return nil, &component.MockError{} + }, + }, nil) + + err := service.Create(MockID, &Component{ + Type: V5, + }) + require.Equal(t, &component.MockError{}, err) +} + +func TestServiceSiteErrorRegistryNotFound(t *testing.T) { + + ctx := context.Background() + + service := NewService(ctx, nil, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, &component.NotFoundError{} + }, + }, &component.MockStore[broker.Source, component.ID]{ + OnGet: func(identifier component.ID) (broker.Source, error) { + return nil, nil + }, + }, &component.MockStore[site.Site, component.ID]{ + OnGet: func(identifier component.ID) (site.Site, error) { + return nil, &component.MockError{} + }, + }) + + err := service.Create(MockID, &Component{ + Type: V5, + }) + require.Equal(t, &component.MockError{}, err) +} + +func TestBrokerConnectionError(t *testing.T) { + + expectedError := `mqtt client with id=MockID could not connect to MQTT broker at endpoint MockEndpoint: "MockError"` + + err := &BrokerConnectionError{ + id: MockID, + endpoint: MockEndpoint, + err: &component.MockError{ + OnError: func() string { + return MockError + }, + }, + } + + require.Equal(t, expectedError, err.Error()) +} + +func TestUnknownClientTypeError(t *testing.T) { + + expectedError := "no such MockName type for mqtt client component" + + err := &UnknownClientTypeError{ + name: MockName, + } + + require.Equal(t, expectedError, err.Error()) +} \ No newline at end of file diff --git a/samples/krill/components/edge/edge_test.go b/samples/krill/components/edge/edge_test.go new file mode 100644 index 0000000..1fcaf14 --- /dev/null +++ b/samples/krill/components/edge/edge_test.go @@ -0,0 +1,202 @@ +package edge + +import ( + "testing" + + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/iot-for-all/device-simulation/lib/composition" + "github.com/stretchr/testify/require" +) + +const ( + MockID = "MockID" + MockParentNodeID = "MockParentNodeID" + MockChildNodeID = "MockChildNodeID" + MockLabelEdgeConfiguration = "MockLabelEdgeConfiguration" + MockPositionEdgeConfiguration = 5 + MockInvalidType = "MockInvalidType" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestStore(t *testing.T) { + store := NewStore() + _, ok := store.(*component.Memstore[composition.Edge, component.ID]) + require.True(t, ok) +} + +func TestEdgeServiceLabel(t *testing.T) { + service := NewService(&component.MockStore[composition.Edge, component.ID]{ + OnCreate: func(entity composition.Edge, identifier component.ID) error { + return nil + }, + }, &component.MockStore[composition.Renderer, component.ID]{ + OnGet: func(identifier component.ID) (composition.Renderer, error) { + if identifier == MockParentNodeID { + return &composition.MockNode{ + OnWith: func(e composition.Edge) composition.Node { + res, ok := e.(*composition.Label) + require.True(t, ok) + require.Equal(t, MockLabelEdgeConfiguration, res.Edge()) + return nil + }, + }, nil + } else { + require.Equal(t, MockChildNodeID, string(identifier)) + } + return nil, nil + }, + }) + + err := service.Create(MockID, &Component{ + ParentNodeId: MockParentNodeID, + ChildNodeId: MockChildNodeID, + Type: LABEL, + Configuration: MockLabelEdgeConfiguration, + }) + require.NoError(t, err) +} + +func TestEdgeServicePosition(t *testing.T) { + service := NewService(&component.MockStore[composition.Edge, component.ID]{ + OnCreate: func(entity composition.Edge, identifier component.ID) error { + return nil + }, + }, &component.MockStore[composition.Renderer, component.ID]{ + OnGet: func(identifier component.ID) (composition.Renderer, error) { + if identifier == MockParentNodeID { + return &composition.MockNode{ + OnWith: func(e composition.Edge) composition.Node { + res, ok := e.(*composition.Position) + require.True(t, ok) + require.Equal(t, MockPositionEdgeConfiguration, res.Edge()) + return nil + }, + }, nil + } else { + require.Equal(t, MockChildNodeID, string(identifier)) + } + return nil, nil + }, + }) + + err := service.Create(MockID, &Component{ + ParentNodeId: MockParentNodeID, + ChildNodeId: MockChildNodeID, + Type: POSITION, + Configuration: MockPositionEdgeConfiguration, + }) + require.NoError(t, err) +} + +func TestEdgeServiceInvalidEdgeType(t *testing.T) { + service := NewService(nil, &component.MockStore[composition.Renderer, component.ID]{ + OnGet: func(identifier component.ID) (composition.Renderer, error) { + return &composition.MockNode{}, nil + }, + }) + + err := service.Create(MockID, &Component{ + ParentNodeId: MockParentNodeID, + Type: MockInvalidType, + }) + require.Equal(t, &InvalidTypeError{ + kind: MockInvalidType, + identifier: MockID, + }, err) +} + +func TestEdgeServiceIdentifierConflict(t *testing.T) { + service := NewService(nil, nil) + + err := service.Create(MockID, &Component{ + ParentNodeId: MockParentNodeID, + ChildNodeId: MockParentNodeID, + Type: MockInvalidType, + }) + require.Equal(t, &IdentifierConflictError{ + invalid: MockParentNodeID, + identifier: MockID, + }, err) +} + +func TestEdgeServiceParentNodeStoreGetError(t *testing.T) { + service := NewService(nil, &component.MockStore[composition.Renderer, component.ID]{ + OnGet: func(identifier component.ID) (composition.Renderer, error) { + return nil, &component.MockError{} + }, + }) + + err := service.Create(MockID, &Component{ + ParentNodeId: MockParentNodeID, + }) + require.Equal(t, &component.MockError{}, err) +} + +func TestEdgeServiceChildNodeStoreGetError(t *testing.T) { + service := NewService(nil, &component.MockStore[composition.Renderer, component.ID]{ + OnGet: func(identifier component.ID) (composition.Renderer, error) { + if identifier == MockParentNodeID { + return &composition.MockNode{}, nil + } + return nil, &component.MockError{} + }, + }) + + err := service.Create(MockID, &Component{ + ParentNodeId: MockParentNodeID, + }) + require.Equal(t, &component.MockError{}, err) +} + +func TestEdgeServiceInvalidParentNodeType(t *testing.T) { + service := NewService(nil, &component.MockStore[composition.Renderer, component.ID]{ + OnGet: func(identifier component.ID) (composition.Renderer, error) { + return &composition.MockRenderer{}, nil + }, + }) + + err := service.Create(MockID, &Component{ + ParentNodeId: MockParentNodeID, + }) + require.Equal(t, &InvalidParentNodeTypeError{ + identifier: MockID, + parentNodeIdentifier: MockParentNodeID, + }, err) +} + +func TestEdgeServiceInvalidLabelConfiguration(t *testing.T) { + service := NewService(nil, &component.MockStore[composition.Renderer, component.ID]{ + OnGet: func(identifier component.ID) (composition.Renderer, error) { + return &composition.MockNode{}, nil + }, + }) + + err := service.Create(MockID, &Component{ + ParentNodeId: MockParentNodeID, + Configuration: MockPositionEdgeConfiguration, + Type: LABEL, + }) + require.Equal(t, &InvalidLabelError{ + identifier: MockID, + }, err) +} + +func TestEdgeServiceInvalidPositionConfiguration(t *testing.T) { + service := NewService(nil, &component.MockStore[composition.Renderer, component.ID]{ + OnGet: func(identifier component.ID) (composition.Renderer, error) { + return &composition.MockNode{}, nil + }, + }) + + err := service.Create(MockID, &Component{ + ParentNodeId: MockParentNodeID, + Configuration: MockLabelEdgeConfiguration, + Type: POSITION, + }) + require.Equal(t, &InvalidPositionError{ + identifier: MockID, + }, err) +} diff --git a/samples/krill/components/edge/errors.go b/samples/krill/components/edge/errors.go new file mode 100644 index 0000000..b0c0560 --- /dev/null +++ b/samples/krill/components/edge/errors.go @@ -0,0 +1,61 @@ +package edge + +import ( + "fmt" + + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/iot-for-all/device-simulation/lib/errors" +) + + +type InvalidPositionError struct { + errors.BadRequest + identifier component.ID +} + +func (err *InvalidPositionError) Error() string { + return fmt.Sprintf("could not create the edge with id %q -- for a position type edge, an integer value must be provided", err.identifier) +} + +type InvalidLabelError struct { + errors.BadRequest + identifier component.ID +} + +func (err *InvalidLabelError) Error() string { + return fmt.Sprintf("could not create the edge with id %q -- for a label type edge, a string value must be provided", err.identifier) +} + +type InvalidTypeError struct { + errors.BadRequest + kind string + identifier component.ID +} + +func (err *InvalidTypeError) Error() string { + return fmt.Sprintf( + "attempted to create a edge (identifier %s) with an invalid edge type %s", + err.identifier, + err.kind, + ) +} + +type InvalidParentNodeTypeError struct { + errors.BadRequest + identifier component.ID + parentNodeIdentifier component.ID +} + +func (err *InvalidParentNodeTypeError) Error() string { + return fmt.Sprintf("the parent node with id %s of the edge with id %s must be of type collection of array", err.parentNodeIdentifier, err.identifier) +} + +type IdentifierConflictError struct { + errors.BadRequest + identifier component.ID + invalid component.ID +} + +func (err *IdentifierConflictError) Error() string { + return fmt.Sprintf("edge with id %s cannot have identical child and parent identifiers (id %s)", err.identifier, err.invalid) +} \ No newline at end of file diff --git a/samples/krill/components/edge/service.go b/samples/krill/components/edge/service.go new file mode 100644 index 0000000..5581107 --- /dev/null +++ b/samples/krill/components/edge/service.go @@ -0,0 +1,97 @@ +package edge + +import ( + "github.com/iot-for-all/device-simulation/components/node" + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/iot-for-all/device-simulation/lib/composition" +) + +type Store component.Store[composition.Edge, component.ID] + +type Type string + +const ( + LABEL Type = "label" + POSITION Type = "position" +) + +type Component struct { + ParentNodeId component.ID + ChildNodeId component.ID + Type Type + Configuration any +} + +func NewStore() Store { + return component.New[composition.Edge, component.ID]() +} + +type Service struct { + Store + nodeStore node.Store +} + +func NewService(store Store, nodeStore node.Store) *Service { + return &Service{ + Store: store, + nodeStore: nodeStore, + } +} + +func (service *Service) Create(id component.ID, c *Component) error { + if c.ParentNodeId == c.ChildNodeId { + return &IdentifierConflictError{ + identifier: id, + invalid: c.ChildNodeId, + } + } + + parent, err := service.nodeStore.Get(c.ParentNodeId) + if err != nil { + return err + } + + parentNode, ok := parent.(composition.Node) + if !ok { + return &InvalidParentNodeTypeError{ + identifier: id, + parentNodeIdentifier: c.ParentNodeId, + } + } + + child, err := service.nodeStore.Get(c.ChildNodeId) + if err != nil { + return err + } + + var edge composition.Edge + switch c.Type { + case LABEL: + val, ok := c.Configuration.(string) + if !ok { + return &InvalidLabelError{ + identifier: id, + } + } + + edge = composition.NewLabel(val, child) + parentNode.With(edge) + case POSITION: + val, ok := c.Configuration.(int) + if !ok { + return &InvalidPositionError{ + identifier: id, + } + } + + edge = composition.NewPosition(val, child) + parentNode.With(edge) + default: + return &InvalidTypeError{ + kind: string(c.Type), + identifier: id, + } + } + + return service.Store.Create(edge, id) +} diff --git a/samples/krill/components/formatter/errors.go b/samples/krill/components/formatter/errors.go new file mode 100644 index 0000000..4b48c1c --- /dev/null +++ b/samples/krill/components/formatter/errors.go @@ -0,0 +1,21 @@ +package formatter + +import ( + "fmt" + + "github.com/iot-for-all/device-simulation/lib/errors" +) + +type InvalidTypeError struct { + errors.BadRequest + identifier string + kind string +} + +func (err *InvalidTypeError) Error() string { + return fmt.Sprintf( + "attempted to create formatter with id %s of non-existent type %s", + err.identifier, + err.kind, + ) +} diff --git a/samples/krill/components/formatter/formatter.go b/samples/krill/components/formatter/formatter.go new file mode 100644 index 0000000..89ee0e6 --- /dev/null +++ b/samples/krill/components/formatter/formatter.go @@ -0,0 +1,198 @@ +// Package formatter provides the implementation of the formatter component of the simulation framework. +package formatter + +import ( + "bytes" + "encoding/csv" + "encoding/json" + "errors" + "io" + + binaryEncoder "github.com/iot-for-all/device-simulation/lib/binary" + "github.com/iot-for-all/device-simulation/lib/flatten" + protoEncoder "github.com/iot-for-all/device-simulation/lib/proto" + "google.golang.org/protobuf/proto" +) + +var ( + ErrCannotFormatCSV = errors.New("the CSV could not be formatted") + ErrInconsistentCSVColumns = errors.New("each row in the CSV should be the same length") + ErrCannotParseBinary = errors.New("binary payloads cannot be parsed") + ErrInvalidBinaryFormatType = errors.New("cannot format this type into binary") +) + +type Formatter interface { + Format(any) ([]byte, error) + Parse([]byte) (any, error) +} + +type MarshallerUnmarshaller interface { + Marshal(v any) ([]byte, error) + Unmarshal(data []byte, v any) error +} + +type Json struct{} + +func (j *Json) Marshal(v any) ([]byte, error) { + return json.Marshal(v) +} + +func (j *Json) Unmarshal(data []byte, v any) error { + return json.Unmarshal(data, v) +} + +type JsonFormatter struct { + Marshaller MarshallerUnmarshaller +} + +func NewJsonFormatter(options ...func(*JsonFormatter)) *JsonFormatter { + formatter := &JsonFormatter{ + Marshaller: &Json{}, + } + + for _, option := range options { + option(formatter) + } + + return formatter +} + +func (formatter *JsonFormatter) Format(a any) ([]byte, error) { + return formatter.Marshaller.Marshal(a) +} + +func (formatter *JsonFormatter) Parse(b []byte) (any, error) { + var res map[string]any + err := formatter.Marshaller.Unmarshal(b, &res) + return res, err +} + +type BinaryFormatter struct { + encoder binaryEncoder.Encoder +} + +func NewBinaryFormatter(encoder binaryEncoder.Encoder) *BinaryFormatter { + return &BinaryFormatter{ + encoder: encoder, + } +} + +func (formatter *BinaryFormatter) Format(a any) ([]byte, error) { + return formatter.encoder.Encode(a) +} + +func (formatter *BinaryFormatter) Parse([]byte) (any, error) { + return nil, ErrCannotParseBinary +} + +type CSVFormatter struct { + flattener flatten.Flattener + CreateWriter func(w io.Writer) Writer +} + +type Writer interface { + WriteAll(records [][]string) error +} + +func NewCSVFormatter(flattener flatten.Flattener, options ...func(*CSVFormatter)) *CSVFormatter { + formatter := &CSVFormatter{ + flattener: flattener, + CreateWriter: func(w io.Writer) Writer { + return csv.NewWriter(w) + }, + } + + for _, option := range options { + option(formatter) + } + + return formatter +} + +func (formatter *CSVFormatter) Format(a any) ([]byte, error) { + + entries, ok := a.([]any) + if !ok { + return nil, ErrCannotFormatCSV + } + + res := make([][]string, len(entries)+1) + + var headers []string + for idx, entry := range entries { + flattened, err := formatter.flattener.Flatten("csv", entry) + if err != nil { + return nil, err + } + + if idx == 0 { + for _, field := range flattened { + headers = append(headers, field.Key) + } + res[0] = headers + } + + if len(headers) != len(flattened) { + return nil, ErrInconsistentCSVColumns + } + + fields := make([]string, len(flattened)) + for idx, field := range flattened { + fields[idx] = field.Value + } + res[idx+1] = fields + } + + buf := bytes.NewBuffer(nil) + + writer := formatter.CreateWriter(buf) + + err := writer.WriteAll(res) + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (formatter *CSVFormatter) Parse(b []byte) (any, error) { + return nil, nil +} + +type ProtobufFormatter struct { + encoder protoEncoder.Encoder +} + +func NewProtobufFormatter(encoder protoEncoder.Encoder) *ProtobufFormatter { + return &ProtobufFormatter{ + encoder: encoder, + } +} + +func (formatter *ProtobufFormatter) Format(a any) ([]byte, error) { + return proto.Marshal(formatter.encoder.Encode(a)) +} + +func (formatter *ProtobufFormatter) Parse(b []byte) (any, error) { + message := new(protoEncoder.Message) + + err := proto.Unmarshal(b, message) + if err != nil { + return nil, err + } + + return formatter.encoder.Decode(message), nil +} + +type MockFormatter struct { + OnFormat func(any) ([]byte, error) + OnParse func([]byte) (any, error) +} + +func (formatter *MockFormatter) Format(a any) ([]byte, error) { + return formatter.OnFormat(a) +} + +func (formatter *MockFormatter) Parse(b []byte) (any, error) { + return formatter.OnParse(b) +} diff --git a/samples/krill/components/formatter/formatter_test.go b/samples/krill/components/formatter/formatter_test.go new file mode 100644 index 0000000..a64f7e3 --- /dev/null +++ b/samples/krill/components/formatter/formatter_test.go @@ -0,0 +1,170 @@ +package formatter + +import ( + "errors" + "io" + "testing" + + "github.com/iot-for-all/device-simulation/lib/binary" + "github.com/iot-for-all/device-simulation/lib/flatten" + "github.com/iot-for-all/device-simulation/lib/proto" + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestBinaryFormatter(t *testing.T) { + expected := 1 + formatter := NewBinaryFormatter(&binary.MockEncoder{ + OnEncode: func(a any) ([]byte, error) { + require.Equal(t, expected, a) + return nil, nil + }, + }) + + _, err := formatter.Format(expected) + require.NoError(t, err) + + _, err = formatter.Parse(nil) + require.Equal(t, ErrCannotParseBinary, err) +} + +func TestCSVFormatter(t *testing.T) { + res := []flatten.Field{ + { + Key: "key", + Value: "value", + }, + } + formatter := NewCSVFormatter(&flatten.MockFlattener{ + OnFlatten: func(parent string, entry any) ([]flatten.Field, error) { + return res, nil + }, + }) + + _, err := formatter.Format(1) + require.Equal(t, ErrCannotFormatCSV, err) + + _, err = formatter.Format([]any{1}) + require.NoError(t, err) +} + +func TestCSVFormatterHeaderError(t *testing.T) { + res := []flatten.Field{ + { + Key: "key", + Value: "value", + }, + } + formatter := NewCSVFormatter(&flatten.MockFlattener{ + OnFlatten: func(parent string, entry any) ([]flatten.Field, error) { + r := res + res = []flatten.Field{ + { + Key: "key", + Value: "value", + }, + { + Key: "key-2", + Value: "value", + }, + } + return r, nil + }, + }) + + _, err := formatter.Format([]any{1, 2}) + require.Equal(t, ErrInconsistentCSVColumns, err) +} + +type MockWriter struct { + writeAll func(records [][]string) error +} + +func (writer *MockWriter) WriteAll(records [][]string) error { + return writer.writeAll(records) +} + +func TestCSVFormatterWriterError(t *testing.T) { + res := []flatten.Field{ + { + Key: "key", + Value: "value", + }, + } + + mockErr := errors.New("mock error") + + formatter := NewCSVFormatter(&flatten.MockFlattener{ + OnFlatten: func(parent string, entry any) ([]flatten.Field, error) { + return res, nil + }, + }, func(c *CSVFormatter) { + c.CreateWriter = func(w io.Writer) Writer { + return &MockWriter{ + writeAll: func(records [][]string) error { + return mockErr + }, + } + } + }) + + _, err := formatter.Format([]any{1}) + require.Equal(t, mockErr, err) +} + +func TestProtobufFormatter(t *testing.T) { + formatter := NewProtobufFormatter(&proto.MockEncoder{ + OnEncode: func(a any) *proto.Message { + return &proto.Message{ + Options: &proto.Message_Integer{ + Integer: 1, + }, + } + }, OnDecode: func(m *proto.Message) any { + return 1 + }, + }) + + res, err := formatter.Format(1) + require.NoError(t, err) + + _, err = formatter.Parse(res) + require.NoError(t, err) + + _, err = formatter.Parse([]byte{0, 0}) + require.Error(t, err) +} + +type MockMarshallerUnmarshaller struct { + OnMarshal func(v any) ([]byte, error) + OnUnmarshal func(data []byte, v any) error +} + +func (marshaller *MockMarshallerUnmarshaller) Marshal(v any) ([]byte, error) { + return marshaller.OnMarshal(v) +} + +func (marshaller *MockMarshallerUnmarshaller) Unmarshal(data []byte, v any) error { + return marshaller.OnUnmarshal(data, v) +} + +func TestJsonFormatter(t *testing.T) { + formatter := NewJsonFormatter(func(jf *JsonFormatter) { + jf.Marshaller = &MockMarshallerUnmarshaller{ + OnMarshal: func(v any) ([]byte, error) { + return nil, nil + }, OnUnmarshal: func(data []byte, v any) error { + return nil + }, + } + }) + + _, err := formatter.Format(nil) + require.NoError(t, err) + + _, err = formatter.Parse(nil) + require.NoError(t, err) +} diff --git a/samples/krill/components/formatter/service.go b/samples/krill/components/formatter/service.go new file mode 100644 index 0000000..9948953 --- /dev/null +++ b/samples/krill/components/formatter/service.go @@ -0,0 +1,63 @@ +package formatter + +import ( + "encoding/binary" + + encoder "github.com/iot-for-all/device-simulation/lib/binary" + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/iot-for-all/device-simulation/lib/flatten" + "github.com/iot-for-all/device-simulation/lib/proto" +) + +type Store component.Store[Formatter, component.ID] + +type Type string + +const ( + JSON Type = "json" + LITTLE_ENDIAN Type = "littleEndian" + BIG_ENDIAN Type = "bigEndian" + CSV Type = "csv" + PROTOBUF Type = "protobuf" +) + +type Component struct { + Type Type +} + +type Service struct { + Store +} + +func NewStore() Store { + return component.New[Formatter, component.ID]() +} + +func NewService(store Store) *Service { + return &Service{ + Store: store, + } +} + +func (service *Service) Create(id component.ID, c *Component) error { + var formatter Formatter + switch c.Type { + case JSON: + formatter = NewJsonFormatter() + case LITTLE_ENDIAN: + formatter = NewBinaryFormatter(encoder.New(binary.LittleEndian)) + case BIG_ENDIAN: + formatter = NewBinaryFormatter(encoder.New(binary.BigEndian)) + case CSV: + formatter = NewCSVFormatter(flatten.New()) + case PROTOBUF: + formatter = NewProtobufFormatter(proto.New()) + default: + return &InvalidTypeError{ + identifier: string(id), + kind: string(c.Type), + } + } + + return service.Store.Create(formatter, id) +} diff --git a/samples/krill/components/formatter/service_test.go b/samples/krill/components/formatter/service_test.go new file mode 100644 index 0000000..d9ebdaa --- /dev/null +++ b/samples/krill/components/formatter/service_test.go @@ -0,0 +1,111 @@ +package formatter + +import ( + "testing" + + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/stretchr/testify/require" +) + +const ( + MockID = "MockID" + MockInvalidType = "MockInvalidType" +) + +func TestStore(t *testing.T) { + store := NewStore() + _, ok := store.(*component.Memstore[Formatter, component.ID]) + require.True(t, ok) +} + +func TestFormatterServiceJSON(t *testing.T) { + service := NewService(&component.MockStore[Formatter, component.ID]{ + OnCreate: func(entity Formatter, identifier component.ID) error { + _, ok := entity.(*JsonFormatter) + require.True(t, ok) + require.Equal(t, MockID, string(identifier)) + return nil + }, + }) + + err := service.Create(MockID, &Component{ + Type: JSON, + }) + require.NoError(t, err) +} + +func TestFormatterServiceLittleEndian(t *testing.T) { + service := NewService(&component.MockStore[Formatter, component.ID]{ + OnCreate: func(entity Formatter, identifier component.ID) error { + _, ok := entity.(*BinaryFormatter) + require.True(t, ok) + require.Equal(t, MockID, string(identifier)) + return nil + }, + }) + + err := service.Create(MockID, &Component{ + Type: LITTLE_ENDIAN, + }) + require.NoError(t, err) +} + +func TestFormatterServiceBigEndian(t *testing.T) { + service := NewService(&component.MockStore[Formatter, component.ID]{ + OnCreate: func(entity Formatter, identifier component.ID) error { + _, ok := entity.(*BinaryFormatter) + require.True(t, ok) + require.Equal(t, MockID, string(identifier)) + return nil + }, + }) + + err := service.Create(MockID, &Component{ + Type: BIG_ENDIAN, + }) + require.NoError(t, err) +} + +func TestFormatterServiceCSV(t *testing.T) { + service := NewService(&component.MockStore[Formatter, component.ID]{ + OnCreate: func(entity Formatter, identifier component.ID) error { + _, ok := entity.(*CSVFormatter) + require.True(t, ok) + require.Equal(t, MockID, string(identifier)) + return nil + }, + }) + + err := service.Create(MockID, &Component{ + Type: CSV, + }) + require.NoError(t, err) +} + +func TestFormatterServiceProtobuf(t *testing.T) { + service := NewService(&component.MockStore[Formatter, component.ID]{ + OnCreate: func(entity Formatter, identifier component.ID) error { + _, ok := entity.(*ProtobufFormatter) + require.True(t, ok) + require.Equal(t, MockID, string(identifier)) + return nil + }, + }) + + err := service.Create(MockID, &Component{ + Type: PROTOBUF, + }) + require.NoError(t, err) +} + +func TestFormatterServiceInvalidType(t *testing.T) { + service := NewService(nil) + + err := service.Create(MockID, &Component{ + Type: MockInvalidType, + }) + require.Equal(t, &InvalidTypeError{ + identifier: MockID, + kind: MockInvalidType, + }, err) +} diff --git a/samples/krill/components/limiter/errors.go b/samples/krill/components/limiter/errors.go new file mode 100644 index 0000000..cf4fc99 --- /dev/null +++ b/samples/krill/components/limiter/errors.go @@ -0,0 +1,25 @@ +package limiter + +import ( + "fmt" + + "github.com/iot-for-all/device-simulation/lib/errors" +) + +type InvalidLimitError struct { + errors.BadRequest + value int +} + +func (err *InvalidLimitError) Error() string { + return fmt.Sprintf("limiter cannot have a limit of less than 1 (provided value %d)", err.value) +} + +type InvalidPeriodSecondsError struct { + errors.BadRequest + value int +} + +func (err *InvalidPeriodSecondsError) Error() string { + return fmt.Sprintf("limiter cannot have a period seconds value of less than 1 (provided value %d)", err.value) +} \ No newline at end of file diff --git a/samples/krill/components/limiter/limiter.go b/samples/krill/components/limiter/limiter.go new file mode 100755 index 0000000..d159791 --- /dev/null +++ b/samples/krill/components/limiter/limiter.go @@ -0,0 +1,121 @@ +package limiter + +import ( + "context" + "time" +) + +type Starter interface { + Start(context.Context) +} + +type Stopper interface { + Stop() +} + +type Limiter[T any] interface { + Starter + Stopper + InputOutput[T] +} + +type InputOutput[T any] interface { + Input() chan<- T + Output() <-chan T +} + +type TimedLimiter[T any] struct { + done chan struct{} + input chan T + output chan T + Limit int + Period time.Duration +} + +func NewTimedLimiter[T any]( + options ...func(*TimedLimiter[T]), +) *TimedLimiter[T] { + limiter := &TimedLimiter[T]{ + input: make(chan T), + output: make(chan T), + done: make(chan struct{}), + Limit: 1, + Period: time.Second, + } + + for _, option := range options { + option(limiter) + } + + return limiter +} + +func (limiter *TimedLimiter[T]) Start(ctx context.Context) { + defer close(limiter.output) + ticker := time.NewTicker(limiter.Period / time.Duration(limiter.Limit)) + defer ticker.Stop() + for { + select { + case <-ticker.C: + next, ok := <-limiter.input + if !ok { + return + } + select { + case limiter.output <- next: + case <-ctx.Done(): + return + } + case <-ctx.Done(): + return + case <-limiter.done: + return + } + } +} + +func (limiter *TimedLimiter[T]) Stop() { + close(limiter.done) +} + +func (limiter *TimedLimiter[T]) Input() chan<- T { + return limiter.input +} + +func (limiter *TimedLimiter[T]) Output() <-chan T { + return limiter.output +} + +type NoopLimiter[T any] struct { + C chan T +} + +func (limiter *NoopLimiter[T]) Start(ctx context.Context) { + <-ctx.Done() +} + +func (limiter *NoopLimiter[T]) Input() chan<- T { + return limiter.C +} + +func (limiter *NoopLimiter[T]) Output() <-chan T { + return limiter.C +} + +func (limiter *NoopLimiter[T]) Stop() {} + +type MockLimiter[T any] struct { + Starter + OnInput func() chan<- T + OnOutput func() <-chan T +} + +func (limiter *MockLimiter[T]) Input() chan<- T { + return limiter.OnInput() +} + +func (limiter *MockLimiter[T]) Output() <-chan T { + return limiter.OnOutput() +} + +func (limiter *MockLimiter[T]) Stop() {} \ No newline at end of file diff --git a/samples/krill/components/limiter/limiter_test.go b/samples/krill/components/limiter/limiter_test.go new file mode 100755 index 0000000..5a2b473 --- /dev/null +++ b/samples/krill/components/limiter/limiter_test.go @@ -0,0 +1,80 @@ +package limiter + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestLimiter(t *testing.T) { + + ctx := context.Background() + + expectedMinimumDurationMs := 4 + reqsPerSecond := 1000 + + limiter := &TimedLimiter[struct{}]{ + Limit: reqsPerSecond, + Period: time.Duration(expectedMinimumDurationMs) * time.Millisecond, + input: make(chan struct{}), + output: make(chan struct{}), + } + + go limiter.Start(ctx) + + done := make(chan struct{}) + + var elapsed time.Duration + + go func() { + start := time.Now() + for count := 0; count < (expectedMinimumDurationMs+1)*reqsPerSecond; count++ { + limiter.Input() <- struct{}{} + <-limiter.Output() + } + elapsed = time.Since(start) + close(done) + }() + + <-done + + require.LessOrEqual( + t, + time.Millisecond*time.Duration(expectedMinimumDurationMs), + elapsed, + ) +} + +func TestLimiterCancellation(t *testing.T) { + + ctx, cancel := context.WithCancel(context.Background()) + + // Enforce extremely slow rate limiting. + limiter := &TimedLimiter[struct{}]{ + Limit: 1, + Period: time.Hour, + input: make(chan struct{}), + output: make(chan struct{}), + } + + go limiter.Start(ctx) + + done := make(chan struct{}) + + go func() { + for count := 0; count < 1000; count++ { + limiter.Input() <- struct{}{} + <-limiter.Output() + } + close(done) + }() + + cancel() + <-limiter.Output() +} \ No newline at end of file diff --git a/samples/krill/components/limiter/service.go b/samples/krill/components/limiter/service.go new file mode 100644 index 0000000..f95e95c --- /dev/null +++ b/samples/krill/components/limiter/service.go @@ -0,0 +1,53 @@ +package limiter + +import ( + "context" + "time" + + "github.com/iot-for-all/device-simulation/lib/component" +) + +type Store component.Store[Limiter[struct{}], component.ID] + +type Component struct { + Limit int + PeriodSeconds int +} + +type Service struct { + Store + ctx context.Context +} + +func NewStore() Store { + return component.New[Limiter[struct{}], component.ID]() +} + +func NewService(ctx context.Context, store Store) *Service { + return &Service{ + Store: store, + ctx: ctx, + } +} + +func (service *Service) Create(id component.ID, c *Component) error { + if c.Limit < 1 { + return &InvalidLimitError{ + value: c.Limit, + } + } + + if c.PeriodSeconds < 1 { + return &InvalidPeriodSecondsError{ + value: c.PeriodSeconds, + } + } + + lim := NewTimedLimiter(func(tl *TimedLimiter[struct{}]) { + tl.Limit = c.Limit + tl.Period = time.Duration(c.PeriodSeconds) * time.Second + }) + go lim.Start(service.ctx) + + return service.Store.Create(lim, id) +} diff --git a/samples/krill/components/limiter/service_test.go b/samples/krill/components/limiter/service_test.go new file mode 100644 index 0000000..e73aa20 --- /dev/null +++ b/samples/krill/components/limiter/service_test.go @@ -0,0 +1,67 @@ +package limiter + +import ( + "context" + "testing" + "time" + + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/stretchr/testify/require" +) + +const ( + MockID = "MockID" + MockLimit = 1 + MockPeriodSeconds = 2 + MockInvalid = 0 +) + +func TestStore(t *testing.T) { + store := NewStore() + _, ok := store.(*component.Memstore[Limiter[struct{}], component.ID]) + require.True(t, ok) +} + +func TestLimiterService(t *testing.T) { + + expectedDuration := time.Duration(MockPeriodSeconds) * time.Second + + service := NewService(context.Background(), &component.MockStore[Limiter[struct{}], component.ID]{ + OnCreate: func(entity Limiter[struct{}], identifier component.ID) error { + res, ok := entity.(*TimedLimiter[struct{}]) + require.True(t, ok) + require.Equal(t, MockLimit, res.Limit) + require.Equal(t, expectedDuration, res.Period) + return nil + }, + }) + + err := service.Create(MockID, &Component{ + PeriodSeconds: MockPeriodSeconds, + Limit: MockLimit, + }) + require.NoError(t, err) +} + +func TestLimiterServiceLimitError(t *testing.T) { + service := NewService(context.Background(), nil) + + err := service.Create(MockID, &Component{ + Limit: MockInvalid, + }) + require.Equal(t, &InvalidLimitError{ + value: MockInvalid, + }, err) +} + +func TestLimiterServicePeriodSecondsError(t *testing.T) { + service := NewService(context.Background(), nil) + + err := service.Create(MockID, &Component{ + Limit: MockLimit, + PeriodSeconds: MockInvalid, + }) + require.Equal(t, &InvalidPeriodSecondsError{ + value: MockInvalid, + }, err) +} diff --git a/samples/krill/components/node/errors.go b/samples/krill/components/node/errors.go new file mode 100644 index 0000000..b2af052 --- /dev/null +++ b/samples/krill/components/node/errors.go @@ -0,0 +1,33 @@ +package node + +import ( + "fmt" + + "github.com/iot-for-all/device-simulation/lib/errors" +) + +type InvalidConfigurationError struct { + errors.BadRequest + identifier string +} + +func (err *InvalidConfigurationError) Error() string { + return fmt.Sprintf( + "attempted to created an expression node with identifier %s with a non-string configuration", + err.identifier, + ) +} + +type InvalidTypeError struct { + errors.BadRequest + kind string + identifier string +} + +func (err *InvalidTypeError) Error() string { + return fmt.Sprintf( + "attempted to create a node (identifier %s) with an invalid node type %s", + err.identifier, + err.kind, + ) +} \ No newline at end of file diff --git a/samples/krill/components/node/node_test.go b/samples/krill/components/node/node_test.go new file mode 100644 index 0000000..5c894a2 --- /dev/null +++ b/samples/krill/components/node/node_test.go @@ -0,0 +1,101 @@ +package node + +import ( + "testing" + + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/iot-for-all/device-simulation/lib/composition" + "github.com/iot-for-all/device-simulation/lib/logger" + "github.com/stretchr/testify/require" +) + +const ( + MockID = "MockID" + MockInvalidType = "MockInvalidType" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestStore(t *testing.T) { + store := NewStore() + _, ok := store.(*component.Memstore[composition.Renderer, component.ID]) + require.True(t, ok) +} + +func TestServiceExpression(t *testing.T) { + service := NewService(&component.MockStore[composition.Renderer, component.ID]{ + OnCreate: func(entity composition.Renderer, identifier component.ID) error { + _, ok := entity.(*composition.Expression) + require.True(t, ok) + return nil + }, + }, func(s *Service) { + s.Logger = &logger.NoopLogger{} + }) + + err := service.Create(MockID, &Component{ + Type: EXPRESSION, + Configuration: "x", + }) + require.NoError(t, err) +} + +func TestServiceCollection(t *testing.T) { + service := NewService(&component.MockStore[composition.Renderer, component.ID]{ + OnCreate: func(entity composition.Renderer, identifier component.ID) error { + _, ok := entity.(*composition.Collection) + require.True(t, ok) + return nil + }, + }) + + err := service.Create(MockID, &Component{ + Type: COLLECTION, + }) + require.NoError(t, err) +} + +func TestServiceArray(t *testing.T) { + service := NewService(&component.MockStore[composition.Renderer, component.ID]{ + OnCreate: func(entity composition.Renderer, identifier component.ID) error { + _, ok := entity.(*composition.Array) + require.True(t, ok) + return nil + }, + }) + + err := service.Create(MockID, &Component{ + Type: ARRAY, + }) + require.NoError(t, err) +} + +func TestServiceTypeError(t *testing.T) { + service := NewService(&component.MockStore[composition.Renderer, component.ID]{ + OnCreate: func(entity composition.Renderer, identifier component.ID) error { + _, ok := entity.(*composition.Array) + require.True(t, ok) + return nil + }, + }) + + err := service.Create(MockID, &Component{ + Type: MockInvalidType, + }) + require.Equal(t, &InvalidTypeError{ + kind: MockInvalidType, + identifier: MockID, + }, err) +} + +func TestServiceExpressionParseError(t *testing.T) { + service := NewService(nil) + + err := service.Create(MockID, &Component{ + Type: EXPRESSION, + Configuration: "", + }) + require.Error(t, err) +} diff --git a/samples/krill/components/node/service.go b/samples/krill/components/node/service.go new file mode 100644 index 0000000..c754951 --- /dev/null +++ b/samples/krill/components/node/service.go @@ -0,0 +1,74 @@ +package node + +import ( + "go/parser" + + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/iot-for-all/device-simulation/lib/composition" + "github.com/iot-for-all/device-simulation/lib/expression" + "github.com/iot-for-all/device-simulation/lib/logger" +) + +type Store component.Store[composition.Renderer, component.ID] + +type Type string + +const ( + EXPRESSION Type = "expression" + COLLECTION Type = "collection" + ARRAY Type = "array" +) + +type Component struct { + Type Type + Configuration string +} + +type Service struct { + Store + Logger logger.Logger +} + +func NewStore() Store { + return component.New[composition.Renderer, component.ID]() +} + +func NewService(store Store, options ...func(*Service)) *Service { + service := &Service{ + Store: store, + Logger: &logger.NoopLogger{}, + } + + for _, option := range options { + option(service) + } + + return service +} + +func (service *Service) Create(id component.ID, c *Component) error { + + var node composition.Renderer + switch c.Type { + case EXPRESSION: + psr, err := parser.ParseExpr(c.Configuration) + if err != nil { + return err + } + + node = composition.NewExpression(expression.New(psr), func(e *composition.Expression) { + e.Logger = service.Logger + }) + case COLLECTION: + node = composition.NewCollection() + case ARRAY: + node = composition.NewArray() + default: + return &InvalidTypeError{ + kind: string(c.Type), + identifier: string(id), + } + } + + return service.Store.Create(node, id) +} diff --git a/samples/krill/components/observer/observer.go b/samples/krill/components/observer/observer.go new file mode 100644 index 0000000..27dbe33 --- /dev/null +++ b/samples/krill/components/observer/observer.go @@ -0,0 +1,56 @@ +package observer + +import ( + "github.com/iot-for-all/device-simulation/components/registry" +) + +// Observer is an implementation of the CancellableObservable interface and serves as the observer component in the simulation framework. +type Observer struct { + observable registry.CancellableObservable + ID int + registry registry.Registry +} + +// NewObserver creates an observer given an observable and a registry. +// It will register the observer with the registry when called. +func NewObserver( + observable registry.CancellableObservable, + registry registry.Registry, +) *Observer { + observer := &Observer{ + observable: observable, + registry: registry, + } + + observer.ID = observer.registry.Register(observer) + + return observer +} + +// Observe will call the observable's observe function, passing through its observed value. +func (observer *Observer) Observe(val float64) { + observer.observable.Observe(val) +} + +// Cancel will deregister the observable from the registry and then cancel the observable. +func (observer *Observer) Cancel() { + observer.registry.Deregister(observer.ID) + observer.observable.Cancel() +} + +type NoopObservable struct{} + +func (*NoopObservable) Observe(val float64) {} + +type MockObserver struct { + OnObserve func(val float64) + OnCancel func() +} + +func (obs *MockObserver) Observe(val float64) { + obs.OnObserve(val) +} + +func (obs *MockObserver) Cancel() { + obs.OnCancel() +} \ No newline at end of file diff --git a/samples/krill/components/observer/observer_test.go b/samples/krill/components/observer/observer_test.go new file mode 100644 index 0000000..7f0c7bd --- /dev/null +++ b/samples/krill/components/observer/observer_test.go @@ -0,0 +1,78 @@ +package observer + +import ( + "testing" + + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestMockObserver(t *testing.T) { + expected := 101.0 + cancelled := make(chan struct{}) + obs := &MockObserver{ + OnObserve: func(val float64) { + require.Equal(t, expected, val) + }, OnCancel: func() { + close(cancelled) + }, + } + + obs.Observe(expected) + go obs.Cancel() + <-cancelled +} + +func TestBasicRegistryAndObserver(t *testing.T) { + + expected := 101.0 + reg := registry.NewRegistry() + cancelled := make(chan struct{}) + observed := make(chan struct{}) + obs := NewObserver(&MockObserver{ + OnObserve: func(val float64) { + require.Equal(t, expected, val) + close(observed) + }, OnCancel: func() { + close(cancelled) + }, + }, reg) + + go reg.Observe(expected) + <-observed + go obs.Cancel() + <-cancelled +} + +func TestRegistryWithMultipleObservables(t *testing.T) { + expected := 101.0 + reg := registry.NewRegistry() + cancelled := make(chan struct{}) + observed := make(chan struct{}) + obsOne := NewObserver(&MockObserver{ + OnObserve: func(val float64) { + require.Equal(t, expected, val) + observed <- struct{}{} + }, OnCancel: func() { + close(cancelled) + }, + }, reg) + NewObserver(&MockObserver{ + OnObserve: func(val float64) { + require.Equal(t, expected, val) + observed <- struct{}{} + }, + }, reg) + + go reg.Observe(expected) + <-observed + <-observed + close(observed) + + go obsOne.Cancel() + <-cancelled +} \ No newline at end of file diff --git a/samples/krill/components/observer/service.go b/samples/krill/components/observer/service.go new file mode 100644 index 0000000..2ae9576 --- /dev/null +++ b/samples/krill/components/observer/service.go @@ -0,0 +1,52 @@ +package observer + +import ( + "github.com/iot-for-all/device-simulation/components/provider" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/lib/component" +) + +type Store component.Store[*Observer, component.ID] + +type Component struct { + RegistryID component.ID + ProviderID component.ID + Label string +} + +type Service struct { + Store + registryStore registry.Store + providerStore provider.Store +} + +func NewStore() Store { + return component.New[*Observer, component.ID]() +} + +func NewService(store Store, registryStore registry.Store, providerStore provider.Store) *Service { + return &Service{ + Store: store, + registryStore: registryStore, + providerStore: providerStore, + } +} + +func (service *Service) Create(id component.ID, c *Component) error { + reg, err := service.registryStore.Get(c.RegistryID) + if err != nil { + return err + } + + prov, err := service.providerStore.Get(c.ProviderID) + if err != nil { + return err + } + + obs, err := prov.With(c.Label) + if err != nil { + return err + } + + return service.Store.Create(NewObserver(obs, reg), id) +} diff --git a/samples/krill/components/observer/service_test.go b/samples/krill/components/observer/service_test.go new file mode 100644 index 0000000..6bff811 --- /dev/null +++ b/samples/krill/components/observer/service_test.go @@ -0,0 +1,116 @@ +package observer + +import ( + "testing" + + "github.com/iot-for-all/device-simulation/components/provider" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/stretchr/testify/require" +) + +const ( + MockID = "MockID" + MockObserverID = 1 + MockLabel = "MockLabel" + MockRegistryID = "MockRegistryID" + MockProviderID = "MockProviderID" +) + +func TestStore(t *testing.T) { + store := NewStore() + _, ok := store.(*component.Memstore[*Observer, component.ID]) + require.True(t, ok) +} + +func TestObserverService(t *testing.T) { + service := NewService(&component.MockStore[*Observer, component.ID]{ + OnCreate: func(entity *Observer, identifier component.ID) error { + require.Equal(t, MockID, string(identifier)) + _, ok := entity.registry.(*registry.MockRegistry) + require.True(t, ok) + _, ok = entity.observable.(*registry.MockObservable) + require.True(t, ok) + require.Equal(t, MockObserverID, entity.ID) + return nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + require.Equal(t, MockRegistryID, string(identifier)) + return ®istry.MockRegistry{ + OnRegister: func(o registry.Observable) int { + res, ok := o.(*Observer) + require.True(t, ok) + _, ok = res.registry.(*registry.MockRegistry) + require.True(t, ok) + _, ok = res.observable.(*registry.MockObservable) + require.True(t, ok) + + return MockObserverID + }, + }, nil + }, + }, &component.MockStore[provider.Provider, component.ID]{ + OnGet: func(identifier component.ID) (provider.Provider, error) { + require.Equal(t, MockProviderID, string(identifier)) + return &provider.MockProvider{ + OnWith: func(label string) (registry.CancellableObservable, error) { + require.Equal(t, MockLabel, label) + return ®istry.MockObservable{}, nil + }, + }, nil + }, + }) + + err := service.Create(MockID, &Component{ + RegistryID: MockRegistryID, + ProviderID: MockProviderID, + Label: MockLabel, + }) + require.NoError(t, err) +} + +func TestObserverServiceRegistryStoreError(t *testing.T) { + service := NewService(nil, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, &component.MockError{} + }, + }, nil) + + err := service.Create(MockID, &Component{}) + require.Equal(t, &component.MockError{}, err) +} + +func TestObserverServiceProviderStoreError(t *testing.T) { + service := NewService(nil, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, nil + }, + }, &component.MockStore[provider.Provider, component.ID]{ + OnGet: func(identifier component.ID) (provider.Provider, error) { + return nil, &component.MockError{} + }, + }) + + err := service.Create(MockID, &Component{}) + require.Equal(t, &component.MockError{}, err) +} + +func TestObserverServiceProviderWithError(t *testing.T) { + service := NewService(nil, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, nil + }, + }, &component.MockStore[provider.Provider, component.ID]{ + OnGet: func(identifier component.ID) (provider.Provider, error) { + return &provider.MockProvider{ + OnWith: func(label string) (registry.CancellableObservable, error) { + return nil, &component.MockError{} + }, + }, nil + }, + }) + + err := service.Create(MockID, &Component{}) + require.Equal(t, &component.MockError{}, err) +} diff --git a/samples/krill/components/outlet/outlet.go b/samples/krill/components/outlet/outlet.go new file mode 100644 index 0000000..035abf1 --- /dev/null +++ b/samples/krill/components/outlet/outlet.go @@ -0,0 +1,70 @@ +package outlet + +import ( + "errors" + + "github.com/iot-for-all/device-simulation/lib/expression" + "github.com/iot-for-all/device-simulation/components/formatter" + "github.com/iot-for-all/device-simulation/components/registry" +) + +var ( + ErrInvalidParsedResultType = errors.New("the observed message body must be parsed into a map of string to any") + ErrInvalidObservationType = errors.New("only floats or integer values can be observed") +) + +type Outlet interface { + Observe([]byte) error +} + +type PrometheusOutlet struct { + expression expression.Evaluator + formatter formatter.Formatter + monitor registry.Observable +} + +func NewPrometheusOutlet( + expr expression.Evaluator, + frmt formatter.Formatter, + monitor registry.Observable, +) *PrometheusOutlet { + return &PrometheusOutlet{ + expression: expr, + formatter: frmt, + monitor: monitor, + } +} + +func (outlet *PrometheusOutlet) Observe(b []byte) error { + res, err := outlet.formatter.Parse(b) + if err != nil { + return err + } + + env, ok := res.(map[string]any) + if !ok { + return ErrInvalidParsedResultType + } + + val, err := outlet.expression.Evaluate(env) + if err != nil { + return err + } + + switch observed := val.(type) { + case float64: + outlet.monitor.Observe(observed) + case int: + outlet.monitor.Observe(float64(observed)) + default: + return ErrInvalidObservationType + } + + return nil +} + +type NoopOutlet struct{} + +func (outlet *NoopOutlet) Observe([]byte) error { + return nil +} diff --git a/samples/krill/components/outlet/outlet_test.go b/samples/krill/components/outlet/outlet_test.go new file mode 100644 index 0000000..a5965b7 --- /dev/null +++ b/samples/krill/components/outlet/outlet_test.go @@ -0,0 +1,85 @@ +package outlet + +import ( + "errors" + "testing" + + "github.com/iot-for-all/device-simulation/lib/expression" + "github.com/iot-for-all/device-simulation/components/formatter" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/stretchr/testify/require" +) + +var ( + ErrMock = errors.New("mock error") +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestPrometheusOutlet(t *testing.T) { + expected := 1.0 + outlet := NewPrometheusOutlet(&expression.MockEvaluator{ + OnEvaluate: func(m map[string]any) (any, error) { + return expected, nil + }, + }, &formatter.MockFormatter{ + OnParse: func(b []byte) (any, error) { + return map[string]any{"": expected}, nil + }, + }, ®istry.MockObservable{ + OnObserve: func(val float64) { + require.Equal(t, expected, val) + }, + }) + + err := outlet.Observe(nil) + require.NoError(t, err) +} + +func TestPrometheusOutletIntCast(t *testing.T) { + expected := 1 + outlet := NewPrometheusOutlet(&expression.MockEvaluator{ + OnEvaluate: func(m map[string]any) (any, error) { + return expected, nil + }, + }, &formatter.MockFormatter{ + OnParse: func(b []byte) (any, error) { + return map[string]any{"": expected}, nil + }, + }, ®istry.MockObservable{ + OnObserve: func(val float64) { + require.Equal(t, 1.0, val) + }, + }) + + err := outlet.Observe(nil) + require.NoError(t, err) +} + +func TestPrometheusOutletFormatterError(t *testing.T) { + outlet := NewPrometheusOutlet(&expression.MockEvaluator{}, &formatter.MockFormatter{ + OnParse: func(b []byte) (any, error) { + return nil, ErrMock + }, + }, ®istry.MockObservable{}) + + err := outlet.Observe(nil) + require.Equal(t, ErrMock, err) +} + +func TestPrometheusOutletEvaluatorError(t *testing.T) { + outlet := NewPrometheusOutlet(&expression.MockEvaluator{ + OnEvaluate: func(m map[string]any) (any, error) { + return nil, ErrMock + }, + }, &formatter.MockFormatter{ + OnParse: func(b []byte) (any, error) { + return map[string]any{"": 0}, nil + }, + }, ®istry.MockObservable{}) + + err := outlet.Observe(nil) + require.Equal(t, ErrMock, err) +} diff --git a/samples/krill/components/outlet/service.go b/samples/krill/components/outlet/service.go new file mode 100644 index 0000000..7934438 --- /dev/null +++ b/samples/krill/components/outlet/service.go @@ -0,0 +1,62 @@ +package outlet + +import ( + "go/parser" + + "github.com/iot-for-all/device-simulation/components/formatter" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/iot-for-all/device-simulation/lib/expression" +) + +type Store component.Store[Outlet, component.ID] + +type Type string + +type Component struct { + RegistryID component.ID + FormatterID component.ID + Type Type + Configuration string +} + +type Service struct { + Store + formatterStore formatter.Store + registryStore registry.Store +} + +func NewStore() Store { + return component.New[Outlet, component.ID]() +} + +func NewService( + store Store, + formatterStore formatter.Store, + registryStore registry.Store, +) *Service { + return &Service{ + Store: store, + formatterStore: formatterStore, + registryStore: registryStore, + } +} + +func (service *Service) Create(id component.ID, c *Component) error { + reg, err := service.registryStore.Get(c.RegistryID) + if err != nil { + return err + } + + fmtr, err := service.formatterStore.Get(c.FormatterID) + if err != nil { + return err + } + + psr, err := parser.ParseExpr(c.Configuration) + if err != nil { + return err + } + + return service.Store.Create(NewPrometheusOutlet(expression.New(psr), fmtr, reg), id) +} diff --git a/samples/krill/components/outlet/service_test.go b/samples/krill/components/outlet/service_test.go new file mode 100644 index 0000000..3428007 --- /dev/null +++ b/samples/krill/components/outlet/service_test.go @@ -0,0 +1,92 @@ +package outlet + +import ( + "testing" + + "github.com/iot-for-all/device-simulation/components/formatter" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/stretchr/testify/require" +) + +const ( + MockID = "MockID" + MockRegistryID = "MockRegistryID" + MockFormatterID = "MockFormatterID" + MockConfiguration = "MockConfiguration" +) + +func TestStore(t *testing.T) { + store := NewStore() + _, ok := store.(*component.Memstore[Outlet, component.ID]) + require.True(t, ok) +} + +func TestService(t *testing.T) { + service := NewService(&component.MockStore[Outlet, component.ID]{ + OnCreate: func(entity Outlet, identifier component.ID) error { + require.Equal(t, MockID, string(identifier)) + _, ok := entity.(*PrometheusOutlet) + require.True(t, ok) + return nil + }, + }, &component.MockStore[formatter.Formatter, component.ID]{ + OnGet: func(identifier component.ID) (formatter.Formatter, error) { + require.Equal(t, MockFormatterID, string(identifier)) + return nil, nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + require.Equal(t, MockRegistryID, string(identifier)) + return nil, nil + }, + }) + + err := service.Create(MockID, &Component{ + RegistryID: MockRegistryID, + FormatterID: MockFormatterID, + Configuration: "MockConfiguration", + }) + require.NoError(t, err) +} + +func TestServiceFormatterError(t *testing.T) { + service := NewService(nil, &component.MockStore[formatter.Formatter, component.ID]{ + OnGet: func(identifier component.ID) (formatter.Formatter, error) { + return nil, &component.MockError{} + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, nil + }, + }) + + err := service.Create(MockID, &Component{}) + require.Equal(t, &component.MockError{}, err) +} + +func TestServiceRegistryError(t *testing.T) { + service := NewService(nil, nil, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, &component.MockError{} + }, + }) + + err := service.Create(MockID, &Component{}) + require.Equal(t, &component.MockError{}, err) +} + +func TestServiceParserError(t *testing.T) { + service := NewService(nil, &component.MockStore[formatter.Formatter, component.ID]{ + OnGet: func(identifier component.ID) (formatter.Formatter, error) { + return nil, nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, nil + }, + }) + + err := service.Create(MockID, &Component{}) + require.Error(t, err) +} diff --git a/samples/krill/components/provider/errors.go b/samples/krill/components/provider/errors.go new file mode 100644 index 0000000..229e875 --- /dev/null +++ b/samples/krill/components/provider/errors.go @@ -0,0 +1,21 @@ +package provider + +import ( + "fmt" + + "github.com/iot-for-all/device-simulation/lib/errors" +) + +type InvalidTypeError struct { + errors.BadRequest + identifier string + kind string +} + +func (err *InvalidTypeError) Error() string { + return fmt.Sprintf( + "could not create the provider component with id %s because an invalid provider type of %s was given", + err.identifier, + err.kind, + ) +} \ No newline at end of file diff --git a/samples/krill/components/provider/provider.go b/samples/krill/components/provider/provider.go new file mode 100644 index 0000000..dfec7f5 --- /dev/null +++ b/samples/krill/components/provider/provider.go @@ -0,0 +1,47 @@ +package provider + +import ( + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/prometheus/client_golang/prometheus" +) + +// Provider is the interface describing the provider component. +// Its implementations should be able to create a CancellableObservable implementation if provided with a label. +type Provider interface { + With(label string) (registry.CancellableObservable, error) + Cancel() error +} + +type MockProvider struct { + OnWith func(label string) (registry.CancellableObservable, error) + OnCancel func() error +} + +func (provider *MockProvider) With( + label string, +) (registry.CancellableObservable, error) { + return provider.OnWith(label) +} + +func (provider *MockProvider) Cancel() error { + return provider.OnCancel() +} + +type MockRegistry struct { + prometheus.Registerer + OnRegister func(prometheus.Collector) error + OnMustRegister func(...prometheus.Collector) + OnUnregister func(prometheus.Collector) bool +} + +func (reg *MockRegistry) Register(c prometheus.Collector) error { + return reg.OnRegister(c) +} + +func (reg *MockRegistry) MustRegister(c ...prometheus.Collector) { + reg.OnMustRegister(c...) +} + +func (reg *MockRegistry) Unregister(c prometheus.Collector) bool { + return reg.OnUnregister(c) +} diff --git a/samples/krill/components/provider/provider_test.go b/samples/krill/components/provider/provider_test.go new file mode 100644 index 0000000..435763b --- /dev/null +++ b/samples/krill/components/provider/provider_test.go @@ -0,0 +1,31 @@ +package provider + +import ( + "testing" + + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestMockProvider(t *testing.T) { + expected := "label" + cancelled := make(chan struct{}) + mock := &MockProvider{ + OnWith: func(label string) (registry.CancellableObservable, error) { + require.Equal(t, expected, label) + return nil, nil + }, OnCancel: func() error { + go close(cancelled) + return nil + }, + } + _, err := mock.With(expected) + require.NoError(t, err) + err = mock.Cancel() + require.NoError(t, err) + <-cancelled +} \ No newline at end of file diff --git a/samples/krill/components/provider/service.go b/samples/krill/components/provider/service.go new file mode 100644 index 0000000..9d57ec7 --- /dev/null +++ b/samples/krill/components/provider/service.go @@ -0,0 +1,110 @@ +package provider + +import ( + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/iot-for-all/device-simulation/lib/counter" + "github.com/iot-for-all/device-simulation/lib/exporter" + "github.com/iot-for-all/device-simulation/lib/gauge" + "github.com/iot-for-all/device-simulation/lib/histogram" + "github.com/iot-for-all/device-simulation/lib/logger" + "github.com/prometheus/client_golang/prometheus" +) + +type Store component.Store[Provider, component.ID] + +type Type string + +const ( + COUNTER Type = "counter" + HISTOGRAM Type = "histogram" + GAUGE Type = "gauge" + CUSTOM_HISTOGRAM Type = "custom_histogram" +) + +type Component struct { + Help string + Name string + Label string + Start float64 + Width float64 + Buckets int + Type Type +} + +type Service struct { + Store + registry prometheus.Registerer + exporter exporter.Exporter + Logger logger.Logger +} + +func NewStore() Store { + return component.New[Provider, component.ID]() +} + +func NewService(store Store, registry prometheus.Registerer, exp exporter.Exporter, options ...func(*Service)) *Service { + service := &Service{ + Store: store, + registry: registry, + exporter: exp, + Logger: &logger.NoopLogger{}, + } + + for _, option := range options { + option(service) + } + + return service +} + +func (service *Service) Create(id component.ID, c *Component) error { + var provider Provider + var err error + switch c.Type { + case COUNTER: + provider, err = counter.New( + service.registry, + func(cp *counter.Provider) { + cp.Name = c.Name + cp.Help = c.Help + }, + ) + case HISTOGRAM: + provider, err = histogram.New( + service.registry, + func(hp *histogram.Provider) { + hp.Name = c.Name + hp.Help = c.Help + hp.Buckets = c.Buckets + hp.Start = c.Start + hp.Width = c.Width + }, + ) + case GAUGE: + provider, err = gauge.New( + service.registry, + func(gp *gauge.Provider) { + gp.Name = c.Name + gp.Help = c.Help + }, + ) + case CUSTOM_HISTOGRAM: + provider, err = exporter.New(service.exporter, func(chp *exporter.CustomHistogramProvider) { + chp.Name = c.Name + chp.Help = c.Help + chp.Start = int(c.Start) + chp.Width = int(c.Width) + chp.Logger = service.Logger + }) + default: + return &InvalidTypeError{ + identifier: string(id), + kind: string(c.Type), + } + } + if err != nil { + return err + } + + return service.Store.Create(provider, id) +} diff --git a/samples/krill/components/provider/service_test.go b/samples/krill/components/provider/service_test.go new file mode 100644 index 0000000..d2df39b --- /dev/null +++ b/samples/krill/components/provider/service_test.go @@ -0,0 +1,192 @@ +package provider + +import ( + "testing" + + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/iot-for-all/device-simulation/lib/counter" + "github.com/iot-for-all/device-simulation/lib/exporter" + "github.com/iot-for-all/device-simulation/lib/gauge" + "github.com/iot-for-all/device-simulation/lib/histogram" + "github.com/iot-for-all/device-simulation/lib/logger" + "github.com/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/require" +) + +const ( + MockID = "MockID" + MockHelp = "MockHelp" + MockName = "MockName" + MockLabel = "MockLabel" + MockInvalidType = "MockInvalidType" + MockStart = 1.0 + MockWidth = 10.0 + MockBuckets = 11 +) + +func TestStore(t *testing.T) { + store := NewStore() + _, ok := store.(*component.Memstore[Provider, component.ID]) + require.True(t, ok) +} + +func TestProviderServiceCounter(t *testing.T) { + service := NewService(&component.MockStore[Provider, component.ID]{ + OnCreate: func(entity Provider, identifier component.ID) error { + res, ok := entity.(*counter.Provider) + require.True(t, ok) + require.Equal(t, MockID, string(identifier)) + require.Equal(t, MockHelp, res.Help) + require.Equal(t, MockName, res.Name) + return nil + }, + }, &MockRegistry{ + OnRegister: func(c prometheus.Collector) error { + return nil + }, + }, &exporter.MockExporter{ + OnRegisterHistogram: func(name, help string, start, width int) (exporter.Provider, error) { + return nil, nil + }, + }, func(s *Service) { + s.Logger = &logger.NoopLogger{} + }) + + err := service.Create(MockID, &Component{ + Help: MockHelp, + Name: MockName, + Label: MockLabel, + Start: MockStart, + Width: MockWidth, + Buckets: MockBuckets, + Type: COUNTER, + }) + require.NoError(t, err) +} + +func TestProviderServiceHistogram(t *testing.T) { + service := NewService(&component.MockStore[Provider, component.ID]{ + OnCreate: func(entity Provider, identifier component.ID) error { + res, ok := entity.(*histogram.Provider) + require.True(t, ok) + require.Equal(t, MockID, string(identifier)) + require.Equal(t, MockHelp, res.Help) + require.Equal(t, MockName, res.Name) + require.Equal(t, MockBuckets, res.Buckets) + require.Equal(t, MockStart, res.Start) + require.Equal(t, MockWidth, res.Width) + return nil + }, + }, &MockRegistry{ + OnRegister: func(c prometheus.Collector) error { + return nil + }, + }, nil) + + err := service.Create(MockID, &Component{ + Help: MockHelp, + Name: MockName, + Label: MockLabel, + Start: MockStart, + Width: MockWidth, + Buckets: MockBuckets, + Type: HISTOGRAM, + }) + require.NoError(t, err) +} + +func TestProviderServiceGauge(t *testing.T) { + service := NewService(&component.MockStore[Provider, component.ID]{ + OnCreate: func(entity Provider, identifier component.ID) error { + res, ok := entity.(*gauge.Provider) + require.True(t, ok) + require.Equal(t, MockID, string(identifier)) + require.Equal(t, MockHelp, res.Help) + require.Equal(t, MockName, res.Name) + return nil + }, + }, &MockRegistry{ + OnRegister: func(c prometheus.Collector) error { + return nil + }, + }, nil) + + err := service.Create(MockID, &Component{ + Help: MockHelp, + Name: MockName, + Label: MockLabel, + Type: GAUGE, + }) + require.NoError(t, err) +} + +func TestProviderServiceCustomHistogram(t *testing.T) { + service := NewService(&component.MockStore[Provider, component.ID]{ + OnCreate: func(entity Provider, identifier component.ID) error { + res, ok := entity.(*exporter.CustomHistogramProvider) + require.True(t, ok) + require.Equal(t, MockID, string(identifier)) + require.Equal(t, MockHelp, res.Help) + require.Equal(t, MockName, res.Name) + require.Equal(t, int(MockStart), res.Start) + require.Equal(t, int(MockWidth), res.Width) + return nil + }, + }, nil, &exporter.MockExporter{ + OnRegisterHistogram: func(name, help string, start, width int) (exporter.Provider, error) { + return nil, nil + }, + }) + + err := service.Create(MockID, &Component{ + Help: MockHelp, + Name: MockName, + Label: MockLabel, + Start: MockStart, + Width: MockWidth, + Buckets: MockBuckets, + Type: CUSTOM_HISTOGRAM, + }) + require.NoError(t, err) +} + +func TestProviderServiceCustomHistogramError(t *testing.T) { + service := NewService(&component.MockStore[Provider, component.ID]{ + OnCreate: func(entity Provider, identifier component.ID) error { + res, ok := entity.(*exporter.CustomHistogramProvider) + require.True(t, ok) + require.Equal(t, MockID, string(identifier)) + require.Equal(t, MockHelp, res.Help) + require.Equal(t, MockName, res.Name) + require.Equal(t, int(MockStart), res.Start) + require.Equal(t, int(MockWidth), res.Width) + return nil + }, + }, nil, &exporter.MockExporter{ + OnRegisterHistogram: func(name, help string, start, width int) (exporter.Provider, error) { + return nil, &component.MockError{} + }, + }) + + err := service.Create(MockID, &Component{ + Help: MockHelp, + Name: MockName, + Label: MockLabel, + Start: MockStart, + Width: MockWidth, + Type: CUSTOM_HISTOGRAM, + }) + require.Equal(t, &component.MockError{}, err) +} + +func TestProviderServiceInvalidTypeError(t *testing.T) { + service := NewService(nil, nil, nil) + + err := service.Create(MockID, &Component{ + Type: MockInvalidType, + }) + require.Equal(t, &InvalidTypeError{ + identifier: MockID, + kind: MockInvalidType, + }, err) +} diff --git a/samples/krill/components/publisher/publisher.go b/samples/krill/components/publisher/publisher.go new file mode 100644 index 0000000..9f3fa89 --- /dev/null +++ b/samples/krill/components/publisher/publisher.go @@ -0,0 +1,148 @@ +// Package publisher provides the implementation for the publisher component of the simulation framework along with all associated interfaces. +package publisher + +import ( + "context" + "time" + + "github.com/iot-for-all/device-simulation/components/client" + "github.com/iot-for-all/device-simulation/components/limiter" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/components/renderer" + "github.com/iot-for-all/device-simulation/components/topic" + "github.com/iot-for-all/device-simulation/components/tracer" + "github.com/iot-for-all/device-simulation/lib/environment" + "github.com/iot-for-all/device-simulation/lib/logger" +) + +// Publisher is a component which routinely publishes messages on a provided topic name. +// It uses a work pool to publish messages. +type Publisher struct { + ctx context.Context + tracer tracer.Tracer + client client.Publisher + renderer renderer.Renderer + topic topic.Renderer + monitor registry.Observable + env environment.Environment + Cancel context.CancelFunc + limiter limiter.Limiter[struct{}] + Logger logger.Logger + QoS int + RendersPerPublish int + MessagesRetained bool + Name string + Site string +} + +// New creates a Publisher given a context, a work pool of type PublishResult, +// a payload to render MQTT message bodies from, a client whose connection will be used to publish messages, +// a topic to render MQTT topic to publish on, and a monitor to observe message publishing latencies with. +// Optional parameters can be set with the options function. +func New( + ctx context.Context, + ren renderer.Renderer, + cli client.Publisher, + top topic.Renderer, + env environment.Environment, + mon registry.Observable, + tra tracer.Tracer, + lim limiter.Limiter[struct{}], + options ...func(*Publisher), +) *Publisher { + publisher := &Publisher{ + client: cli, + topic: top, + renderer: ren, + ctx: ctx, + monitor: mon, + env: env, + limiter: lim, + tracer: tra, + Logger: &logger.NoopLogger{}, + RendersPerPublish: 1, + } + + for _, option := range options { + option(publisher) + } + + publisher.env.Set("x", -1) + publisher.env.Set("start", time.Now()) + publisher.env.Set("site", publisher.Site) + publisher.env.Set("id", publisher.Name) + + ctx, cancel := context.WithCancel(publisher.ctx) + publisher.Cancel = cancel + publisher.ctx = ctx + + return publisher +} + +func (publisher *Publisher) publish(ctx context.Context) error { + + data, err := publisher.renderer.Render( + publisher.env, + publisher.env.Env()["x"].(int)+1, + publisher.RendersPerPublish, + ) + if err != nil { + return err + } + + start := time.Now() + + res := make(chan error) + block := publisher.tracer.Begin() + go func() { + res <- publisher.client.Publish( + publisher.topic.Render(), + byte(publisher.QoS), + publisher.MessagesRetained, + data, + ) + }() + + select { + case <-ctx.Done(): + return nil + case err := <-res: + acknowledgementLatency := time.Since(start) + + publisher.monitor.Observe( + float64(acknowledgementLatency.Milliseconds()), + ) + publisher.topic.Observe(float64(acknowledgementLatency.Milliseconds())) + publisher.client.Observe(float64(acknowledgementLatency.Milliseconds())) + + <-block + + return err + } +} + +// Start will begin the operation of the publisher, only starting to send messages once the underlying client is successfully connected to an MQTT broker. +// It will return if its context is cancelled, or if the underlying client is disconnected. +func (publisher *Publisher) Start() { + <-publisher.client.Connected() + input := publisher.limiter.Input() + output := publisher.limiter.Output() + + errorLvl := publisher.Logger.Level(logger.Error) + + for { + select { + case <-publisher.ctx.Done(): + return + case <-publisher.client.Disconnected(): + return + case input <- struct{}{}: + case <-output: + err := publisher.publish(publisher.ctx) + if err != nil { + errorLvl.With("error", err.Error()). + Printf("error publishing message") + } + } + } +} \ No newline at end of file diff --git a/samples/krill/components/publisher/publisher_test.go b/samples/krill/components/publisher/publisher_test.go new file mode 100644 index 0000000..8d7c551 --- /dev/null +++ b/samples/krill/components/publisher/publisher_test.go @@ -0,0 +1,156 @@ +package publisher + +import ( + "context" + "testing" + + "github.com/iot-for-all/device-simulation/components/client" + "github.com/iot-for-all/device-simulation/components/formatter" + "github.com/iot-for-all/device-simulation/components/limiter" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/components/renderer" + "github.com/iot-for-all/device-simulation/components/topic" + "github.com/iot-for-all/device-simulation/components/tracer" + "github.com/iot-for-all/device-simulation/lib/composition" + "github.com/iot-for-all/device-simulation/lib/environment" + "github.com/iot-for-all/device-simulation/lib/errors" + "github.com/iot-for-all/device-simulation/lib/logger" + + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestPublisher(t *testing.T) { + + ctx := context.Background() + + lim := &limiter.NoopLimiter[struct{}]{ + C: make(chan struct{}, 1), + } + + reg := registry.NewRegistry() + + ren := renderer.New(composition.NewCollection(), formatter.NewJsonFormatter()) + + top := topic.New(reg) + + finished := make(chan struct{}) + + cli := &client.MockClient{ + OnConnect: make(chan struct{}), + OnPublish: func(topic string, qos byte, messagesRetained bool, data []byte) error { + finished <- struct{}{} + return nil + }, Observable: reg, + } + go close(cli.OnConnect) + + env := environment.New() + + publisher := New(ctx, ren, cli, top, env, reg, tracer.NewNoopTracer(), lim, func(p *Publisher) { + p.QoS = 1 + }) + go publisher.Start() + <-finished +} + +func TestPublisherWithPublishError(t *testing.T) { + + ctx := context.Background() + + lim := &limiter.NoopLimiter[struct{}]{ + C: make(chan struct{}, 1), + } + + reg := registry.NewRegistry() + + ren := renderer.New(composition.NewCollection(), formatter.NewJsonFormatter()) + top := topic.New(reg) + cli := &client.MockClient{ + OnConnect: make(chan struct{}), + OnPublish: func(topic string, qos byte, messagesRetained bool, data []byte) error { + return errors.Mock{} + }, Observable: reg, + } + go close(cli.OnConnect) + + finished := make(chan struct{}) + + lg := &logger.MockLogger{ + OnLevel: func(i int) logger.Logger { + return &logger.MockLogger{ + OnWith: func(s1, s2 string) logger.Logger { + require.Equal(t, errors.Mock{}.Error(), s2) + finished <- struct{}{} + return &logger.NoopLogger{} + }, + } + }, + } + + env := environment.New() + + publisher := New(ctx, ren, cli, top, env, reg, tracer.NewNoopTracer(), lim, func(p *Publisher) { + p.QoS = 1 + p.Logger = lg + }) + go publisher.Start() + <-finished +} + +func TestPublisherDisconnectViaClientDisconnect(t *testing.T) { + + ctx := context.Background() + lim := &limiter.NoopLimiter[struct{}]{ + C: make(chan struct{}, 1), + } + reg := registry.NewRegistry() + ren := renderer.New(composition.NewCollection(), formatter.NewJsonFormatter()) + top := topic.New(reg) + cli := &client.MockClient{ + OnConnect: make(chan struct{}), + OnDisconnect: make(chan struct{}), + Observable: reg, + OnPublish: func(topic string, qos byte, messagesRetained bool, data []byte) error { + return nil + }, + } + go close(cli.OnConnect) + + env := environment.New() + + publisher := New(ctx, ren, cli, top, env, reg, tracer.NewNoopTracer(), lim) + + go close(cli.OnDisconnect) + publisher.Start() +} + +func TestPublisherDisconnectViaCancellation(t *testing.T) { + + ctx := context.Background() + lim := &limiter.NoopLimiter[struct{}]{ + C: make(chan struct{}, 1), + } + reg := registry.NewRegistry() + ren := renderer.New(composition.NewCollection(), formatter.NewJsonFormatter()) + top := topic.New(reg) + cli := &client.MockClient{ + OnConnect: make(chan struct{}), + OnDisconnect: make(chan struct{}), + Observable: reg, + OnPublish: func(topic string, qos byte, messagesRetained bool, data []byte) error { + return nil + }, + } + go close(cli.OnConnect) + + env := environment.New() + + publisher := New(ctx, ren, cli, top, env, reg, tracer.NewNoopTracer(), lim) + + go publisher.Cancel() + publisher.Start() +} \ No newline at end of file diff --git a/samples/krill/components/publisher/service.go b/samples/krill/components/publisher/service.go new file mode 100644 index 0000000..bfbd60f --- /dev/null +++ b/samples/krill/components/publisher/service.go @@ -0,0 +1,140 @@ +package publisher + +import ( + "context" + + "github.com/iot-for-all/device-simulation/components/client" + "github.com/iot-for-all/device-simulation/components/limiter" + "github.com/iot-for-all/device-simulation/components/observer" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/components/renderer" + "github.com/iot-for-all/device-simulation/components/topic" + "github.com/iot-for-all/device-simulation/components/tracer" + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/iot-for-all/device-simulation/lib/environment" + "github.com/iot-for-all/device-simulation/lib/logger" +) + +type Store component.Store[*Publisher, component.ID] + +type Component struct { + RegistryID component.ID + ClientID component.ID + TopicID component.ID + RendererID component.ID + LimiterID component.ID + TracerID component.ID + QoSLevel int + RendersPerPublish int + MessagesRetained bool +} + +type Service struct { + Store + registryStore registry.Store + clientStore client.Store + topicStore topic.Store + rendererStore renderer.Store + limiterStore limiter.Store + tracerStore tracer.Store + ctx context.Context + Logger logger.Logger +} + +func NewStore() Store { + return component.New[*Publisher, component.ID]() +} + +func NewService( + ctx context.Context, + store Store, + registryStore registry.Store, + clientStore client.Store, + topicStore topic.Store, + rendererStore renderer.Store, + limiterStore limiter.Store, + tracerStore tracer.Store, + options ...func(*Service), +) *Service { + service := &Service{ + Store: store, + registryStore: registryStore, + clientStore: clientStore, + topicStore: topicStore, + rendererStore: rendererStore, + limiterStore: limiterStore, + tracerStore: tracerStore, + ctx: ctx, + Logger: &logger.NoopLogger{}, + } + + for _, option := range options { + option(service) + } + + return service +} + +func (service *Service) Create(id component.ID, c *Component) error { + var reg registry.Observable + reg, err := service.registryStore.Get(c.RegistryID) + if err != nil { + _, ok := err.(*component.NotFoundError) + if !ok { + return err + } + reg = &observer.NoopObservable{} + } + + var tra tracer.Tracer + tra, err = service.tracerStore.Get(c.TracerID) + if err != nil { + _, ok := err.(*component.NotFoundError) + if !ok { + return err + } + tra = tracer.NewNoopTracer() + } + + cli, err := service.clientStore.Get(c.ClientID) + if err != nil { + return err + } + + top, err := service.topicStore.Get(c.TopicID) + if err != nil { + return err + } + + lim, err := service.limiterStore.Get(c.LimiterID) + if err != nil { + return err + } + + ren, err := service.rendererStore.Get(c.RendererID) + if err != nil { + return err + } + + pub := New( + service.ctx, + ren, + cli, + top, + environment.New(), + reg, + tra, + lim, + func(p *Publisher) { + p.QoS = c.QoSLevel + p.RendersPerPublish = c.RendersPerPublish + p.MessagesRetained = c.MessagesRetained + p.Logger = service.Logger + p.Name = cli.GetName() + p.Site = cli.Render() + }, + ) + go pub.Start() + + return service.Store.Create(pub, id) +} diff --git a/samples/krill/components/publisher/service_test.go b/samples/krill/components/publisher/service_test.go new file mode 100644 index 0000000..e6bd925 --- /dev/null +++ b/samples/krill/components/publisher/service_test.go @@ -0,0 +1,228 @@ +package publisher + +import ( + "context" + "testing" + + "github.com/iot-for-all/device-simulation/components/client" + "github.com/iot-for-all/device-simulation/components/limiter" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/components/renderer" + "github.com/iot-for-all/device-simulation/components/topic" + "github.com/iot-for-all/device-simulation/components/tracer" + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/iot-for-all/device-simulation/lib/logger" + "github.com/stretchr/testify/require" +) + +const ( + MockID = "MockID" + MockRegistryID = "MockRegistryID" + MockClientID = "MockClientID" + MockTopicID = "MockTopicID" + MockRendererID = "MockRendererID" + MockLimiterID = "MockLimiterID" + MockTracerID = "MockTracerID" + MockName = "MockName" + MockSite = "MockSite" + MockQoSLevel = 1 + MockRendersPerPublish = 1 + MockMessagesRetained = true +) + +func TestStore(t *testing.T) { + store := NewStore() + _, ok := store.(*component.Memstore[*Publisher, component.ID]) + require.True(t, ok) +} + +func TestPublisherService(t *testing.T) { + service := NewService(context.Background(), &component.MockStore[*Publisher, component.ID]{ + OnCreate: func(entity *Publisher, identifier component.ID) error { + require.Equal(t, MockName, entity.Name) + require.Equal(t, MockSite, entity.Site) + require.Equal(t, MockQoSLevel, entity.QoS) + require.Equal(t, MockRendersPerPublish, entity.RendersPerPublish) + require.Equal(t, MockMessagesRetained, entity.MessagesRetained) + require.Equal(t, MockID, string(identifier)) + return nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + require.Equal(t, MockRegistryID, string(identifier)) + return nil, nil + }, + }, &component.MockStore[client.PublisherSubscriber, component.ID]{ + OnGet: func(identifier component.ID) (client.PublisherSubscriber, error) { + require.Equal(t, MockClientID, string(identifier)) + return &client.MockClient{ + OnGetName: func() string { + return MockName + }, OnRender: func() string { + return MockSite + }, + }, nil + }, + }, &component.MockStore[topic.Renderer, component.ID]{ + OnGet: func(identifier component.ID) (topic.Renderer, error) { + require.Equal(t, MockTopicID, string(identifier)) + return nil, nil + }, + }, &component.MockStore[renderer.Renderer, component.ID]{ + OnGet: func(identifier component.ID) (renderer.Renderer, error) { + require.Equal(t, MockRendererID, string(identifier)) + return nil, nil + }, + }, &component.MockStore[limiter.Limiter[struct{}], component.ID]{ + OnGet: func(identifier component.ID) (limiter.Limiter[struct{}], error) { + require.Equal(t, MockLimiterID, string(identifier)) + return nil, nil + }, + }, &component.MockStore[tracer.Tracer, component.ID]{ + OnGet: func(identifier component.ID) (tracer.Tracer, error) { + require.Equal(t, MockTracerID, string(identifier)) + return nil, nil + }, + }, func(s *Service) { + s.Logger = &logger.NoopLogger{} + }) + + err := service.Create(MockID, &Component{ + RegistryID: MockRegistryID, + ClientID: MockClientID, + TopicID: MockTopicID, + RendererID: MockRendererID, + LimiterID: MockLimiterID, + TracerID: MockTracerID, + QoSLevel: MockQoSLevel, + RendersPerPublish: MockRendersPerPublish, + MessagesRetained: MockMessagesRetained, + }) + require.NoError(t, err) +} + +func TestPublisherServiceClientStoreError(t *testing.T) { + service := NewService(context.Background(), nil, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, &component.NotFoundError{} + }, + }, &component.MockStore[client.PublisherSubscriber, component.ID]{ + OnGet: func(identifier component.ID) (client.PublisherSubscriber, error) { + return nil, &component.MockError{} + }, + }, nil, nil, nil, &component.MockStore[tracer.Tracer, component.ID]{ + OnGet: func(identifier component.ID) (tracer.Tracer, error) { + return nil, &component.NotFoundError{} + }, + }) + + err := service.Create(MockID, &Component{}) + require.Equal(t, &component.MockError{}, err) +} + +func TestPublisherServiceTopicStoreError(t *testing.T) { + service := NewService(context.Background(), nil, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, nil + }, + }, &component.MockStore[client.PublisherSubscriber, component.ID]{ + OnGet: func(identifier component.ID) (client.PublisherSubscriber, error) { + return nil, nil + }, + }, &component.MockStore[topic.Renderer, component.ID]{ + OnGet: func(identifier component.ID) (topic.Renderer, error) { + return nil, &component.MockError{} + }, + }, nil, nil, &component.MockStore[tracer.Tracer, component.ID]{ + OnGet: func(identifier component.ID) (tracer.Tracer, error) { + return nil, nil + }, + }) + + err := service.Create(MockID, &Component{}) + require.Equal(t, &component.MockError{}, err) +} + +func TestPublisherServiceLimiterStoreError(t *testing.T) { + service := NewService(context.Background(), nil, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, nil + }, + }, &component.MockStore[client.PublisherSubscriber, component.ID]{ + OnGet: func(identifier component.ID) (client.PublisherSubscriber, error) { + return nil, nil + }, + }, &component.MockStore[topic.Renderer, component.ID]{ + OnGet: func(identifier component.ID) (topic.Renderer, error) { + return nil, nil + }, + }, nil, &component.MockStore[limiter.Limiter[struct{}], component.ID]{ + OnGet: func(identifier component.ID) (limiter.Limiter[struct{}], error) { + return nil, &component.MockError{} + }, + }, &component.MockStore[tracer.Tracer, component.ID]{ + OnGet: func(identifier component.ID) (tracer.Tracer, error) { + return nil, nil + }, + }) + + err := service.Create(MockID, &Component{}) + require.Equal(t, &component.MockError{}, err) +} + +func TestPublisherServiceRendererStoreError(t *testing.T) { + service := NewService(context.Background(), nil, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, nil + }, + }, &component.MockStore[client.PublisherSubscriber, component.ID]{ + OnGet: func(identifier component.ID) (client.PublisherSubscriber, error) { + return nil, nil + }, + }, &component.MockStore[topic.Renderer, component.ID]{ + OnGet: func(identifier component.ID) (topic.Renderer, error) { + return nil, nil + }, + }, &component.MockStore[renderer.Renderer, component.ID]{ + OnGet: func(identifier component.ID) (renderer.Renderer, error) { + return nil, &component.MockError{} + }, + }, &component.MockStore[limiter.Limiter[struct{}], component.ID]{ + OnGet: func(identifier component.ID) (limiter.Limiter[struct{}], error) { + return nil, nil + }, + }, &component.MockStore[tracer.Tracer, component.ID]{ + OnGet: func(identifier component.ID) (tracer.Tracer, error) { + return nil, nil + }, + }) + + err := service.Create(MockID, &Component{}) + require.Equal(t, &component.MockError{}, err) +} + +func TestPublisherServiceTracerStoreError(t *testing.T) { + service := NewService(context.Background(), nil, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, nil + }, + }, nil, nil, nil, nil, &component.MockStore[tracer.Tracer, component.ID]{ + OnGet: func(identifier component.ID) (tracer.Tracer, error) { + return nil, &component.MockError{} + }, + }) + + err := service.Create(MockID, &Component{}) + require.Equal(t, &component.MockError{}, err) +} + +func TestPublisherServiceRegistryStoreError(t *testing.T) { + service := NewService(context.Background(), nil, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, &component.MockError{} + }, + }, nil, nil, nil, nil, nil) + + err := service.Create(MockID, &Component{}) + require.Equal(t, &component.MockError{}, err) +} diff --git a/samples/krill/components/registry/registry.go b/samples/krill/components/registry/registry.go new file mode 100644 index 0000000..97eb170 --- /dev/null +++ b/samples/krill/components/registry/registry.go @@ -0,0 +1,107 @@ +// Package registry contains the implementation of the monitor and observer components as well as other functionality related to configurable metrics and observability. +package registry + +import "sync" + +// Observable is an interface whose implementation should be able to observe a float64 value. +type Observable interface { + Observe(value float64) +} + +// Observable is an interface whose implementation should be able to observe a float64 value. +type CancellableObservable interface { + Observable + Cancel() +} + +// Registry is an interface whose implementation should be able to register and deregister observables. +type Registry interface { + Register(Observable) int + Deregister(int) +} + +type ObservableRegistry interface { + Observable + Registry +} + +// ObserverRegistry is an implementation of both Registry and Observable. +type ObserverRegistry struct { + observables map[int]Observable + mu sync.RWMutex + next int +} + +// NewRegistry will create an ObserverRegistry. +func NewRegistry() *ObserverRegistry { + return &ObserverRegistry{ + observables: make(map[int]Observable), + } +} + +// Register will add an observable to the registry's map, returning an identifier for that observable. +func (registry *ObserverRegistry) Register(observable Observable) int { + registry.mu.Lock() + defer registry.mu.Unlock() + next := registry.next + registry.observables[next] = observable + registry.next++ + return next +} + +// Deregister will remove an observable from the registry's map, given an identifier for that observable. +func (registry *ObserverRegistry) Deregister(identifier int) { + registry.mu.Lock() + defer registry.mu.Unlock() + delete(registry.observables, identifier) +} + +// Observe will call the observe function for all currently registered observables. +func (registry *ObserverRegistry) Observe(val float64) { + registry.mu.RLock() + defer registry.mu.RUnlock() + for _, observer := range registry.observables { + observer.Observe(val) + } +} + +type NoopRegistry struct{} + +func (reg *NoopRegistry) Register(Observable) int { + return 0 +} + +func (reg *NoopRegistry) Deregister(int) {} + +func (reg *NoopRegistry) Observe(value float64) {} + +type MockRegistry struct { + OnRegister func(Observable) int + OnDeregister func(int) + OnObserve func(float64) +} + +func (reg *MockRegistry) Register(o Observable) int { + return reg.OnRegister(o) +} + +func (reg *MockRegistry) Deregister(i int) { + reg.OnDeregister(i) +} + +func (reg *MockRegistry) Observe(f float64) { + reg.OnObserve(f) +} + +type MockObservable struct { + OnObserve func(val float64) + OnCancel func() +} + +func (obs *MockObservable) Observe(val float64) { + obs.OnObserve(val) +} + +func (obs *MockObservable) Cancel() { + obs.OnCancel() +} diff --git a/samples/krill/components/registry/registry_test.go b/samples/krill/components/registry/registry_test.go new file mode 100644 index 0000000..0926bb5 --- /dev/null +++ b/samples/krill/components/registry/registry_test.go @@ -0,0 +1,58 @@ +package registry + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestBasicRegistry(t *testing.T) { + + expected := 101.0 + reg := NewRegistry() + observed := make(chan struct{}) + obs := &MockObservable{ + OnObserve: func(val float64) { + require.Equal(t, expected, val) + close(observed) + }, + } + + reg.Register(obs) + + go reg.Observe(expected) + <-observed + + require.Equal(t, 1, len(reg.observables)) +} + +func TestRegistryWithMultipleObservables(t *testing.T) { + expected := 101.0 + reg := NewRegistry() + observed := make(chan struct{}) + obsOne := &MockObservable{ + OnObserve: func(val float64) { + require.Equal(t, expected, val) + observed <- struct{}{} + }, + } + obsTwo := &MockObservable{ + OnObserve: func(val float64) { + require.Equal(t, expected, val) + observed <- struct{}{} + }, + } + reg.Register(obsOne) + reg.Register(obsTwo) + + go reg.Observe(expected) + <-observed + <-observed + close(observed) + + require.Equal(t, 2, len(reg.observables)) +} \ No newline at end of file diff --git a/samples/krill/components/registry/service.go b/samples/krill/components/registry/service.go new file mode 100644 index 0000000..f81dca1 --- /dev/null +++ b/samples/krill/components/registry/service.go @@ -0,0 +1,28 @@ +package registry + +import ( + "github.com/iot-for-all/device-simulation/lib/component" +) + +type Store component.Store[ObservableRegistry, component.ID] + +type Component struct{} + +type Service struct { + Store +} + +func NewStore() Store { + return component.New[ObservableRegistry, component.ID]() +} + +func NewService(store Store) *Service { + return &Service{ + Store: store, + } +} + +func (service *Service) Create(id component.ID, c *Component) error { + return service.Store.Create( + NewRegistry(), id) +} diff --git a/samples/krill/components/registry/service_test.go b/samples/krill/components/registry/service_test.go new file mode 100644 index 0000000..260ef71 --- /dev/null +++ b/samples/krill/components/registry/service_test.go @@ -0,0 +1,27 @@ +package registry + +import ( + "testing" + + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/stretchr/testify/require" +) + +const MockID = "MockID" + +func TestStore(t *testing.T) { + store := NewStore() + _, ok := store.(*component.Memstore[ObservableRegistry, component.ID]) + require.True(t, ok) +} + +func TestService(t *testing.T) { + service := NewService(&component.MockStore[ObservableRegistry, component.ID]{ + OnCreate: func(entity ObservableRegistry, identifier component.ID) error { + require.Equal(t, MockID, string(identifier)) + return nil + }, + }) + + require.NoError(t, service.Create(MockID, nil)) +} diff --git a/samples/krill/components/renderer/renderer.go b/samples/krill/components/renderer/renderer.go new file mode 100644 index 0000000..a1f7cfd --- /dev/null +++ b/samples/krill/components/renderer/renderer.go @@ -0,0 +1,40 @@ +package renderer + +import ( + "github.com/iot-for-all/device-simulation/components/formatter" + "github.com/iot-for-all/device-simulation/lib/composition" + "github.com/iot-for-all/device-simulation/lib/environment" +) + +type Renderer interface { + Render(environment.Environment, int, int) ([]byte, error) +} + +type NodeRenderer struct { + node composition.Renderer + formatter formatter.Formatter +} + +func New(nd composition.Renderer, frmt formatter.Formatter) *NodeRenderer { + return &NodeRenderer{ + node: nd, + formatter: frmt, + } +} + +func (renderer *NodeRenderer) Render( + env environment.Environment, + start, rows int, +) ([]byte, error) { + + res := make([]any, rows) + + for idx := 0; idx < rows; idx++ { + env.Set("x", start+idx) + rendered := renderer.node.Render(env.Env()) + res[idx] = rendered + env.Set("p", rendered) + } + + return renderer.formatter.Format(res) +} \ No newline at end of file diff --git a/samples/krill/components/renderer/renderer_test.go b/samples/krill/components/renderer/renderer_test.go new file mode 100644 index 0000000..f5d46a5 --- /dev/null +++ b/samples/krill/components/renderer/renderer_test.go @@ -0,0 +1,47 @@ +package renderer + +import ( + "testing" + + "github.com/iot-for-all/device-simulation/components/formatter" + "github.com/iot-for-all/device-simulation/lib/composition" + "github.com/iot-for-all/device-simulation/lib/environment" + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestRenderer(t *testing.T) { + expected := 1 + expectedArr := []any{expected, expected} + renderer := New(&composition.MockRenderer{ + OnRender: func(m map[string]any) any { + require.Equal(t, expected, m[""]) + return expected + }, + }, &formatter.MockFormatter{ + OnFormat: func(a any) ([]byte, error) { + require.Equal(t, expectedArr, a) + return nil, nil + }, + }) + + count := 0 + + _, err := renderer.Render(&environment.MockEnvironment{ + OnSet: func(s string, a any) { + if s == "x" { + require.Equal(t, count, a) + count++ + } else { + require.Equal(t, expected, a) + } + }, OnEnv: func() map[string]any { + return map[string]any{"": expected} + }, + }, 0, 2) + + require.NoError(t, err) +} \ No newline at end of file diff --git a/samples/krill/components/renderer/service.go b/samples/krill/components/renderer/service.go new file mode 100644 index 0000000..a613f65 --- /dev/null +++ b/samples/krill/components/renderer/service.go @@ -0,0 +1,47 @@ +package renderer + +import ( + "github.com/iot-for-all/device-simulation/components/formatter" + "github.com/iot-for-all/device-simulation/components/node" + "github.com/iot-for-all/device-simulation/lib/component" +) + +type Store component.Store[Renderer, component.ID] + +type Component struct { + FormatterID component.ID + NodeID component.ID +} + +type Service struct { + Store + formatterStore formatter.Store + nodeStore node.Store +} + +func NewStore() Store { + return component.New[Renderer, component.ID]() +} + +func NewService(store Store, formatterStore formatter.Store, nodeStore node.Store) *Service { + return &Service{ + Store: store, + formatterStore: formatterStore, + nodeStore: nodeStore, + } +} + +func (service *Service) Create(id component.ID, c *Component) error { + + fmtr, err := service.formatterStore.Get(c.FormatterID) + if err != nil { + return err + } + + nd, err := service.nodeStore.Get(c.NodeID) + if err != nil { + return err + } + + return service.Store.Create(New(nd, fmtr), id) +} diff --git a/samples/krill/components/renderer/service_test.go b/samples/krill/components/renderer/service_test.go new file mode 100644 index 0000000..3febf36 --- /dev/null +++ b/samples/krill/components/renderer/service_test.go @@ -0,0 +1,79 @@ +package renderer + +import ( + "testing" + + "github.com/iot-for-all/device-simulation/components/formatter" + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/iot-for-all/device-simulation/lib/composition" + "github.com/stretchr/testify/require" +) + +const ( + MockID = "MockID" + MockFormatterID = "MockFormatterID" + MockNodeID = "MockNodeID" +) + +func TestStore(t *testing.T) { + store := NewStore() + _, ok := store.(*component.Memstore[Renderer, component.ID]) + require.True(t, ok) +} + +func TestRendererService(t *testing.T) { + service := NewService(&component.MockStore[Renderer, component.ID]{ + OnCreate: func(entity Renderer, identifier component.ID) error { + require.Equal(t, MockID, string(identifier)) + return nil + }, + }, &component.MockStore[formatter.Formatter, component.ID]{ + OnGet: func(identifier component.ID) (formatter.Formatter, error) { + require.Equal(t, MockFormatterID, string(identifier)) + return nil, nil + }, + }, &component.MockStore[composition.Renderer, component.ID]{ + OnGet: func(identifier component.ID) (composition.Renderer, error) { + require.Equal(t, MockNodeID, string(identifier)) + return nil, nil + }, + }) + + err := service.Create(MockID, &Component{ + FormatterID: MockFormatterID, + NodeID: MockNodeID, + }) + require.NoError(t, err) +} + +func TestRendererServiceNodeStoreError(t *testing.T) { + service := NewService(nil, &component.MockStore[formatter.Formatter, component.ID]{ + OnGet: func(identifier component.ID) (formatter.Formatter, error) { + return nil, nil + }, + }, &component.MockStore[composition.Renderer, component.ID]{ + OnGet: func(identifier component.ID) (composition.Renderer, error) { + return nil, &component.MockError{} + }, + }) + + err := service.Create(MockID, &Component{ + FormatterID: MockFormatterID, + NodeID: MockNodeID, + }) + require.Equal(t, &component.MockError{}, err) +} + +func TestRendererServiceFormatterStoreError(t *testing.T) { + service := NewService(nil, &component.MockStore[formatter.Formatter, component.ID]{ + OnGet: func(identifier component.ID) (formatter.Formatter, error) { + return nil, &component.MockError{} + }, + }, nil) + + err := service.Create(MockID, &Component{ + FormatterID: MockFormatterID, + NodeID: MockNodeID, + }) + require.Equal(t, &component.MockError{}, err) +} diff --git a/samples/krill/components/site/service.go b/samples/krill/components/site/service.go new file mode 100644 index 0000000..274d95a --- /dev/null +++ b/samples/krill/components/site/service.go @@ -0,0 +1,46 @@ +package site + +import ( + "github.com/iot-for-all/device-simulation/components/observer" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/lib/component" +) + +type Store component.Store[Site, component.ID] + +type Component struct { + Name string + RegistryID component.ID +} + +type Service struct { + Store + registryStore registry.Store +} + +func NewStore() Store { + return component.New[Site, component.ID]() +} + +func NewService(store Store, registryStore registry.Store) *Service { + return &Service{ + Store: store, + registryStore: registryStore, + } +} + +func (service *Service) Create(id component.ID, c *Component) error { + var reg registry.Observable + reg, err := service.registryStore.Get(c.RegistryID) + if err != nil { + _, ok := err.(*component.NotFoundError) + if !ok { + return err + } + reg = &observer.NoopObservable{} + } + + return service.Store.Create(New(reg, func(ss *StaticSite) { + ss.Name = c.Name + }), id) +} diff --git a/samples/krill/components/site/service_test.go b/samples/krill/components/site/service_test.go new file mode 100644 index 0000000..6bcd42a --- /dev/null +++ b/samples/krill/components/site/service_test.go @@ -0,0 +1,74 @@ +package site + +import ( + "testing" + + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/stretchr/testify/require" +) + +const ( + MockID = "MockID" + MockRegistryID = "MockRegistryID" + MockSiteName = "MockSiteName" +) + +func TestStore(t *testing.T) { + store := NewStore() + _, ok := store.(*component.Memstore[Site, component.ID]) + require.True(t, ok) +} + +func TestSiteService(t *testing.T) { + service := NewService(&component.MockStore[Site, component.ID]{ + OnCreate: func(entity Site, identifier component.ID) error { + require.Equal(t, MockID, string(identifier)) + require.Equal(t, MockSiteName, entity.Render()) + return nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + require.Equal(t, MockRegistryID, string(identifier)) + return nil, nil + }, + }) + + err := service.Create(MockID, &Component{ + Name: MockSiteName, + RegistryID: MockRegistryID, + }) + require.NoError(t, err) +} + +func TestSiteServiceRegistryError(t *testing.T) { + service := NewService(nil, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, &component.MockError{} + }, + }) + + err := service.Create(MockID, &Component{}) + require.Equal(t, &component.MockError{}, err) +} + +func TestSiteServiceNoopRegistry(t *testing.T) { + service := NewService(&component.MockStore[Site, component.ID]{ + OnCreate: func(entity Site, identifier component.ID) error { + require.Equal(t, MockID, string(identifier)) + require.Equal(t, MockSiteName, entity.Render()) + return nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + require.Equal(t, MockRegistryID, string(identifier)) + return nil, &component.NotFoundError{} + }, + }) + + err := service.Create(MockID, &Component{ + Name: MockSiteName, + RegistryID: MockRegistryID, + }) + require.NoError(t, err) +} diff --git a/samples/krill/components/site/site.go b/samples/krill/components/site/site.go new file mode 100644 index 0000000..b92f704 --- /dev/null +++ b/samples/krill/components/site/site.go @@ -0,0 +1,43 @@ +// Package site provides the implementation of the site component of the simulation framework. +package site + +import "github.com/iot-for-all/device-simulation/components/registry" + +type Site interface { + Render() string + registry.Observable +} + +// Site is a representation of a place where many devices/clients may be present. +// It implements the observable interface, allowing for monitoring of all devices within a site. +type StaticSite struct { + registry.Observable + Name string +} + +// New creates a new site, given an observable monitor. +// Optional parameters can be set through the option function. +func New(mon registry.Observable, options ...func(*StaticSite)) *StaticSite { + site := &StaticSite{ + Observable: mon, + } + + for _, option := range options { + option(site) + } + + return site +} + +func (site *StaticSite) Render() string { + return site.Name +} + +type MockSite struct { + OnRender func() string + registry.Observable +} + +func (site *MockSite) Render() string { + return site.OnRender() +} diff --git a/samples/krill/components/site/site_test.go b/samples/krill/components/site/site_test.go new file mode 100644 index 0000000..38b8097 --- /dev/null +++ b/samples/krill/components/site/site_test.go @@ -0,0 +1,17 @@ +package site + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestSite(t *testing.T) { + site := New(nil) + + require.Equal(t, "", site.Name) +} diff --git a/samples/krill/components/subscriber/service.go b/samples/krill/components/subscriber/service.go new file mode 100644 index 0000000..031686e --- /dev/null +++ b/samples/krill/components/subscriber/service.go @@ -0,0 +1,116 @@ +package subscriber + +import ( + "github.com/iot-for-all/device-simulation/components/client" + "github.com/iot-for-all/device-simulation/components/observer" + "github.com/iot-for-all/device-simulation/components/outlet" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/components/topic" + "github.com/iot-for-all/device-simulation/components/tracer" + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/iot-for-all/device-simulation/lib/logger" +) + +type Store component.Store[*Subscriber, component.ID] + +type Component struct { + ClientID component.ID + TopicID component.ID + OutletID component.ID + RegistryID component.ID + TracerID component.ID + QoSLevel int +} + +type Service struct { + Store + clientStore client.Store + topicStore topic.Store + outletStore outlet.Store + registryStore registry.Store + tracerStore tracer.Store + Logger logger.Logger +} + +func NewStore() Store { + return component.New[*Subscriber, component.ID]() +} + +func NewService( + store Store, + clientStore client.Store, + topicStore topic.Store, + outletStore outlet.Store, + registryStore registry.Store, + tracerStore tracer.Store, + options ...func(*Service), +) *Service { + service := &Service{ + Store: store, + clientStore: clientStore, + topicStore: topicStore, + outletStore: outletStore, + registryStore: registryStore, + tracerStore: tracerStore, + Logger: &logger.NoopLogger{}, + } + + for _, option := range options { + option(service) + } + + return service +} + +func (service *Service) Create(id component.ID, c *Component) error { + var reg registry.Observable + reg, err := service.registryStore.Get(c.RegistryID) + if err != nil { + _, ok := err.(*component.NotFoundError) + if !ok { + return err + } + reg = &observer.NoopObservable{} + } + + var tra tracer.Tracer + tra, err = service.tracerStore.Get(c.TracerID) + if err != nil { + _, ok := err.(*component.NotFoundError) + if !ok { + return err + } + tra = tracer.NewNoopTracer() + } + + var out outlet.Outlet + out, err = service.outletStore.Get(c.OutletID) + if err != nil { + _, ok := err.(*component.NotFoundError) + if !ok { + return err + } + out = &outlet.NoopOutlet{} + } + + cli, err := service.clientStore.Get(c.ClientID) + if err != nil { + return err + } + + top, err := service.topicStore.Get(c.TopicID) + if err != nil { + return err + } + + sub := New(cli, top, out, reg, tra, func(s *Subscriber) { + s.QoS = c.QoSLevel + s.Logger = service.Logger.With("topic", top.Render()).With("client", cli.GetName()).With("site", cli.Render()) + }) + err = sub.Start() + if err != nil { + return err + } + + return service.Store.Create(sub, id) +} diff --git a/samples/krill/components/subscriber/service_test.go b/samples/krill/components/subscriber/service_test.go new file mode 100644 index 0000000..d73306b --- /dev/null +++ b/samples/krill/components/subscriber/service_test.go @@ -0,0 +1,267 @@ +package subscriber + +import ( + "testing" + + "github.com/iot-for-all/device-simulation/components/client" + "github.com/iot-for-all/device-simulation/components/outlet" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/components/topic" + "github.com/iot-for-all/device-simulation/components/tracer" + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/iot-for-all/device-simulation/lib/logger" + "github.com/stretchr/testify/require" +) + +const ( + MockID = "MockID" + MockClientID = "MockClientID" + MockTopicID = "MockTopicID" + MockOutletID = "MockOutletID" + MockRegistryID = "MockRegistryID" + MockTracerID = "MockTracerID" + MockName = "MockName" + MockTopic = "MockTopic" + MockSiteName = "MockSiteName" + MockQoSLevel = 1 +) + +func TestStore(t *testing.T) { + store := NewStore() + _, ok := store.(*component.Memstore[*Subscriber, component.ID]) + require.True(t, ok) +} + +func TestService(t *testing.T) { + service := NewService(&component.MockStore[*Subscriber, component.ID]{ + OnCreate: func(entity *Subscriber, identifier component.ID) error { + require.Equal(t, MockID, string(identifier)) + return nil + }, + }, &component.MockStore[client.PublisherSubscriber, component.ID]{ + OnGet: func(identifier component.ID) (client.PublisherSubscriber, error) { + require.Equal(t, MockClientID, string(identifier)) + return &MockClient{ + PublisherSubscriber: &client.MockClient{ + OnGetName: func() string { + return MockName + }, OnRender: func() string { + return MockSiteName + }, OnSubscribe: func(topic string, qos byte, onReceived func([]byte)) error { + require.Equal(t, MockTopic, topic) + require.Equal(t, byte(MockQoSLevel), qos) + return nil + }, + }, OnConnected: func() chan struct{} { + c := make(chan struct{}) + close(c) + return c + }, OnDisconnected: func() chan struct{} { + c := make(chan struct{}) + close(c) + return c + }, + }, nil + }, + }, &component.MockStore[topic.Renderer, component.ID]{ + OnGet: func(identifier component.ID) (topic.Renderer, error) { + require.Equal(t, MockTopicID, string(identifier)) + return &topic.Topic{ + Topic: MockTopic, + }, nil + }, + }, &component.MockStore[outlet.Outlet, component.ID]{ + OnGet: func(identifier component.ID) (outlet.Outlet, error) { + require.Equal(t, MockOutletID, string(identifier)) + return nil, nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + require.Equal(t, MockRegistryID, string(identifier)) + return nil, nil + }, + }, &component.MockStore[tracer.Tracer, component.ID]{ + OnGet: func(identifier component.ID) (tracer.Tracer, error) { + require.Equal(t, MockTracerID, string(identifier)) + return nil, nil + }, + }, func(s *Service) { + s.Logger = &logger.NoopLogger{} + }) + + err := service.Create(MockID, &Component{ + ClientID: MockClientID, + TopicID: MockTopicID, + OutletID: MockOutletID, + RegistryID: MockRegistryID, + TracerID: MockTracerID, + QoSLevel: MockQoSLevel, + }) + + require.NoError(t, err) +} + +func TestServiceSubscriptionError(t *testing.T) { + service := NewService(&component.MockStore[*Subscriber, component.ID]{ + OnCreate: func(entity *Subscriber, identifier component.ID) error { + require.Equal(t, MockID, string(identifier)) + return nil + }, + }, &component.MockStore[client.PublisherSubscriber, component.ID]{ + OnGet: func(identifier component.ID) (client.PublisherSubscriber, error) { + require.Equal(t, MockClientID, string(identifier)) + return &MockClient{ + PublisherSubscriber: &client.MockClient{ + OnGetName: func() string { + return MockName + }, OnRender: func() string { + return MockSiteName + }, OnSubscribe: func(topic string, qos byte, onReceived func([]byte)) error { + return &component.MockError{} + }, + }, OnConnected: func() chan struct{} { + c := make(chan struct{}) + close(c) + return c + }, OnDisconnected: func() chan struct{} { + c := make(chan struct{}) + close(c) + return c + }, + }, nil + }, + }, &component.MockStore[topic.Renderer, component.ID]{ + OnGet: func(identifier component.ID) (topic.Renderer, error) { + require.Equal(t, MockTopicID, string(identifier)) + return &topic.Topic{ + Topic: MockTopic, + }, nil + }, + }, &component.MockStore[outlet.Outlet, component.ID]{ + OnGet: func(identifier component.ID) (outlet.Outlet, error) { + require.Equal(t, MockOutletID, string(identifier)) + return nil, nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + require.Equal(t, MockRegistryID, string(identifier)) + return nil, nil + }, + }, &component.MockStore[tracer.Tracer, component.ID]{ + OnGet: func(identifier component.ID) (tracer.Tracer, error) { + require.Equal(t, MockTracerID, string(identifier)) + return nil, nil + }, + }) + + err := service.Create(MockID, &Component{ + ClientID: MockClientID, + TopicID: MockTopicID, + OutletID: MockOutletID, + RegistryID: MockRegistryID, + TracerID: MockTracerID, + QoSLevel: MockQoSLevel, + }) + + require.Equal(t, &component.MockError{}, err) +} + +func TestServiceTopicStoreError(t *testing.T) { + service := NewService(nil, &component.MockStore[client.PublisherSubscriber, component.ID]{ + OnGet: func(identifier component.ID) (client.PublisherSubscriber, error) { + return nil, nil + }, + }, &component.MockStore[topic.Renderer, component.ID]{ + OnGet: func(identifier component.ID) (topic.Renderer, error) { + return nil, &component.MockError{} + }, + }, &component.MockStore[outlet.Outlet, component.ID]{ + OnGet: func(identifier component.ID) (outlet.Outlet, error) { + return nil, nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, nil + }, + }, &component.MockStore[tracer.Tracer, component.ID]{ + OnGet: func(identifier component.ID) (tracer.Tracer, error) { + return nil, nil + }, + }) + + err := service.Create(MockID, &Component{}) + + require.Equal(t, &component.MockError{}, err) +} + +func TestServiceClientStoreError(t *testing.T) { + service := NewService(nil, &component.MockStore[client.PublisherSubscriber, component.ID]{ + OnGet: func(identifier component.ID) (client.PublisherSubscriber, error) { + return nil, &component.MockError{} + }, + }, nil, &component.MockStore[outlet.Outlet, component.ID]{ + OnGet: func(identifier component.ID) (outlet.Outlet, error) { + return nil, &component.NotFoundError{} + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, &component.NotFoundError{} + }, + }, &component.MockStore[tracer.Tracer, component.ID]{ + OnGet: func(identifier component.ID) (tracer.Tracer, error) { + return nil, &component.NotFoundError{} + }, + }) + + err := service.Create(MockID, &Component{}) + + require.Equal(t, &component.MockError{}, err) +} + +func TestServiceOutletStoreError(t *testing.T) { + service := NewService(nil, nil, nil, &component.MockStore[outlet.Outlet, component.ID]{ + OnGet: func(identifier component.ID) (outlet.Outlet, error) { + return nil, &component.MockError{} + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, nil + }, + }, &component.MockStore[tracer.Tracer, component.ID]{ + OnGet: func(identifier component.ID) (tracer.Tracer, error) { + return nil, nil + }, + }) + + err := service.Create(MockID, &Component{}) + + require.Equal(t, &component.MockError{}, err) +} + +func TestServiceTracerStoreError(t *testing.T) { + service := NewService(nil, nil, nil, nil, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, nil + }, + }, &component.MockStore[tracer.Tracer, component.ID]{ + OnGet: func(identifier component.ID) (tracer.Tracer, error) { + return nil, &component.MockError{} + }, + }) + + err := service.Create(MockID, &Component{}) + + require.Equal(t, &component.MockError{}, err) +} + +func TestServiceRegistryStoreError(t *testing.T) { + service := NewService(nil, nil, nil, nil, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, &component.MockError{} + }, + }, nil) + + err := service.Create(MockID, &Component{}) + + require.Equal(t, &component.MockError{}, err) +} \ No newline at end of file diff --git a/samples/krill/components/subscriber/subscriber.go b/samples/krill/components/subscriber/subscriber.go new file mode 100644 index 0000000..0c14c3a --- /dev/null +++ b/samples/krill/components/subscriber/subscriber.go @@ -0,0 +1,115 @@ +// Package subscriber provides the implementation for the subscriber component of the simulation framework. +package subscriber + +import ( + "fmt" + + "github.com/iot-for-all/device-simulation/components/client" + "github.com/iot-for-all/device-simulation/components/outlet" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/components/topic" + "github.com/iot-for-all/device-simulation/components/tracer" + "github.com/iot-for-all/device-simulation/lib/logger" +) + +type ClientConnectionClosedError struct { + client string +} + +func (err *ClientConnectionClosedError) Error() string { + return fmt.Sprintf( + "the connection of client with id %s was already closed before unsubscribing", + err.client, + ) +} + +// Subscriber is a component which listens for incoming messages on an MQTT broker whose connection +// is provided by the underlying client component. +type Subscriber struct { + client client.PublisherSubscriber + topic topic.Renderer + tracer tracer.Tracer + outlet outlet.Outlet + monitor registry.Observable + Logger logger.Logger + onReceive func([]byte) + QoS int +} + +// New creates a Subscriber, given a client and topic component. +// Optional parameters can be set using the options function. +func New( + cli client.PublisherSubscriber, + top topic.Renderer, + out outlet.Outlet, + mon registry.Observable, + tra tracer.Tracer, + options ...func(*Subscriber), +) *Subscriber { + + subscriber := &Subscriber{ + client: cli, + topic: top, + outlet: out, + monitor: mon, + tracer: tra, + Logger: &logger.NoopLogger{}, + QoS: 0, + } + + for _, option := range options { + option(subscriber) + } + + errLvl := subscriber.Logger.Level(logger.Error) + traceLvl := subscriber.Logger.Level(logger.Trace) + + subscriber.onReceive = func(b []byte) { + traceLvl.Printf("received new message") + subscriber.monitor.Observe(0) + err := subscriber.outlet.Observe(b) + if err != nil { + errLvl.With("error", err.Error()). + Printf("error occurred when observing received message") + } + subscriber.tracer.Received() + } + + return subscriber +} + +// Start will wait until the underlying client is connected, and then subscribe to the originally provided topic once connected. +func (subscriber *Subscriber) Start() error { + <-subscriber.client.Connected() + return subscriber.client.Subscribe( + subscriber.topic.Render(), + byte(subscriber.QoS), + subscriber.onReceive, + ) +} + +// Cancel will return an error if the client is already disconnected, and will attempt to unsubscribe if not. +func (subscriber *Subscriber) Cancel() error { + select { + case <-subscriber.client.Disconnected(): + return &ClientConnectionClosedError{ + client: subscriber.client.GetName(), + } + default: + return subscriber.client.Unsubscribe(subscriber.topic.Render()) + } +} + +type MockClient struct { + client.PublisherSubscriber + OnConnected func() chan struct{} + OnDisconnected func() chan struct{} +} + +func (client *MockClient) Connected() chan struct{} { + return client.OnConnected() +} + +func (client *MockClient) Disconnected() chan struct{} { + return client.OnDisconnected() +} diff --git a/samples/krill/components/subscriber/subscriber_test.go b/samples/krill/components/subscriber/subscriber_test.go new file mode 100644 index 0000000..da0d3de --- /dev/null +++ b/samples/krill/components/subscriber/subscriber_test.go @@ -0,0 +1,152 @@ +package subscriber + +import ( + "testing" + + "github.com/iot-for-all/device-simulation/components/client" + "github.com/iot-for-all/device-simulation/components/outlet" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/components/topic" + "github.com/iot-for-all/device-simulation/components/tracer" + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestSubscribeAfterClientConnection(t *testing.T) { + onSub := make(chan struct{}) + cli := &client.MockClient{ + OnSubscribe: func(topic string, qos byte, onReceived func([]byte)) error { + close(onSub) + return nil + }, OnUnsubscribe: func(topic string) error { + return nil + }, OnDisconnect: make(chan struct{}), + OnConnect: make(chan struct{}), + } + sub := New(cli, topic.New(nil), &outlet.NoopOutlet{}, ®istry.NoopRegistry{}, tracer.NewNoopTracer()) + go func() { + err := sub.Start() + require.NoError(t, err) + }() + err := cli.Connect() + require.NoError(t, err) + <-onSub +} + +func TestReceivedChannelWithBlocking(t *testing.T) { + onSub := make(chan struct{}) + cli := &client.MockClient{ + OnSubscribe: func(topic string, qos byte, onReceived func([]byte)) error { + close(onSub) + onReceived(nil) + return nil + }, OnUnsubscribe: func(topic string) error { + return nil + }, OnDisconnect: make(chan struct{}), + OnConnect: make(chan struct{}), + } + sub := New( + cli, + topic.New(nil), + &outlet.NoopOutlet{}, + ®istry.NoopRegistry{}, + tracer.NewNoopTracer(), + func(s *Subscriber) {}, + ) + go func() { + err := sub.Start() + require.NoError(t, err) + }() + err := cli.Connect() + require.NoError(t, err) + <-onSub +} + +func TestReceivedChannelWithoutBlocking(t *testing.T) { + onSub := make(chan struct{}) + afterOnReceivedCalled := make(chan struct{}) + cli := &client.MockClient{ + OnSubscribe: func(topic string, qos byte, onReceived func([]byte)) error { + close(onSub) + onReceived(nil) + close(afterOnReceivedCalled) + return nil + }, OnUnsubscribe: func(topic string) error { + return nil + }, OnDisconnect: make(chan struct{}), + OnConnect: make(chan struct{}), + } + sub := New(cli, topic.New(nil), &outlet.NoopOutlet{}, ®istry.NoopRegistry{}, tracer.NewNoopTracer()) + go func() { + err := sub.Start() + require.NoError(t, err) + }() + err := cli.Connect() + require.NoError(t, err) + <-onSub + <-afterOnReceivedCalled +} + +func TestSubscriberCancelBeforeClientCancel(t *testing.T) { + onSub := make(chan struct{}) + onUnsub := make(chan struct{}) + + cli := &client.MockClient{ + OnSubscribe: func(topic string, qos byte, onReceived func([]byte)) error { + close(onSub) + return nil + }, OnUnsubscribe: func(topic string) error { + close(onUnsub) + return nil + }, OnDisconnect: make(chan struct{}), + OnConnect: make(chan struct{}), + } + sub := New(cli, topic.New(nil), &outlet.NoopOutlet{}, ®istry.NoopRegistry{}, tracer.NewNoopTracer()) + go func() { + require.NoError(t, sub.Start()) + }() + err := cli.Connect() + require.NoError(t, err) + <-onSub + err = sub.Cancel() + require.NoError(t, err) + <-onUnsub +} + +func TestSubscriberCancelAfterClientCancel(t *testing.T) { + onSub := make(chan struct{}) + onDisconnect := make(chan struct{}) + name := "name" + + cli := &client.MockClient{ + OnSubscribe: func(topic string, qos byte, onReceived func([]byte)) error { + close(onSub) + return nil + }, OnUnsubscribe: func(topic string) error { + return nil + }, OnDisconnect: onDisconnect, + OnConnect: make(chan struct{}), + OnGetName: func() string { + return name + }, + } + sub := New(cli, topic.New(nil), &outlet.NoopOutlet{}, ®istry.NoopRegistry{}, tracer.NewNoopTracer()) + go func() { + require.NoError(t, sub.Start()) + }() + err := cli.Connect() + require.NoError(t, err) + <-onSub + go func() { + err := cli.Disconnect() + require.NoError(t, err) + }() + <-onDisconnect + err = sub.Cancel() + require.Equal(t, ClientConnectionClosedError{ + client: name, + }, *err.(*ClientConnectionClosedError)) +} \ No newline at end of file diff --git a/samples/krill/components/topic/service.go b/samples/krill/components/topic/service.go new file mode 100644 index 0000000..185f667 --- /dev/null +++ b/samples/krill/components/topic/service.go @@ -0,0 +1,46 @@ +package topic + +import ( + "github.com/iot-for-all/device-simulation/components/observer" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/lib/component" +) + +type Store component.Store[Renderer, component.ID] + +type Component struct { + RegistryID component.ID + Name string +} + +type Service struct { + Store + registryStore registry.Store +} + +func NewStore() Store { + return component.New[Renderer, component.ID]() +} + +func NewService(store Store, registryStore registry.Store) *Service { + return &Service{ + Store: store, + registryStore: registryStore, + } +} + +func (service *Service) Create(id component.ID, c *Component) error { + var reg registry.Observable + reg, err := service.registryStore.Get(c.RegistryID) + if err != nil { + _, ok := err.(*component.NotFoundError) + if !ok { + return err + } + reg = &observer.NoopObservable{} + } + + return service.Store.Create(New(reg, func(t *Topic) { + t.Topic = c.Name + }), id) +} diff --git a/samples/krill/components/topic/service_test.go b/samples/krill/components/topic/service_test.go new file mode 100644 index 0000000..95d4ebd --- /dev/null +++ b/samples/krill/components/topic/service_test.go @@ -0,0 +1,74 @@ +package topic + +import ( + "testing" + + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/stretchr/testify/require" +) + +const ( + MockID = "MockID" + MockRegistryID = "MockRegistryID" + MockTopic = "MockTopic" +) + +func TestStore(t *testing.T) { + store := NewStore() + _, ok := store.(*component.Memstore[Renderer, component.ID]) + require.True(t, ok) +} + +func TestTopicService(t *testing.T) { + service := NewService(&component.MockStore[Renderer, component.ID]{ + OnCreate: func(entity Renderer, identifier component.ID) error { + require.Equal(t, MockID, string(identifier)) + require.Equal(t, MockTopic, entity.Render()) + return nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + require.Equal(t, MockRegistryID, string(identifier)) + return nil, nil + }, + }) + + err := service.Create(MockID, &Component{ + Name: MockTopic, + RegistryID: MockRegistryID, + }) + require.NoError(t, err) +} + +func TestTopicServiceNoopRegistry(t *testing.T) { + service := NewService(&component.MockStore[Renderer, component.ID]{ + OnCreate: func(entity Renderer, identifier component.ID) error { + require.Equal(t, MockID, string(identifier)) + require.Equal(t, MockTopic, entity.Render()) + return nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + require.Equal(t, MockRegistryID, string(identifier)) + return nil, &component.NotFoundError{} + }, + }) + + err := service.Create(MockID, &Component{ + Name: MockTopic, + RegistryID: MockRegistryID, + }) + require.NoError(t, err) +} + +func TestTopicServiceRegistryError(t *testing.T) { + service := NewService(nil, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, &component.MockError{} + }, + }) + + err := service.Create(MockID, &Component{}) + require.Equal(t, &component.MockError{}, err) +} diff --git a/samples/krill/components/topic/topic.go b/samples/krill/components/topic/topic.go new file mode 100644 index 0000000..d0594b6 --- /dev/null +++ b/samples/krill/components/topic/topic.go @@ -0,0 +1,38 @@ +// Package topic provides the implementation for the topic component of the simulation framework. +package topic + +import ( + "github.com/iot-for-all/device-simulation/components/registry" +) + +// Renderer is an interface whose implementation should be able to render a topic name when called and should also implement the registry observable interface. +type Renderer interface { + Render() string + registry.Observable +} + +// Topic is an implementation of the Renderer interface which has the ability to render a predefined topic name when its Render function is called. +type Topic struct { + Topic string + registry.Observable +} + +// New creates a topic given an observable. +// Optional parameters can be provided using the options function. +func New(mon registry.Observable, options ...func(*Topic)) *Topic { + topic := &Topic{ + Topic: "/", + Observable: mon, + } + + for _, option := range options { + option(topic) + } + + return topic +} + +// Render returns the predefined topic name. +func (topic *Topic) Render() string { + return topic.Topic +} diff --git a/samples/krill/components/topic/topic_test.go b/samples/krill/components/topic/topic_test.go new file mode 100644 index 0000000..bb70409 --- /dev/null +++ b/samples/krill/components/topic/topic_test.go @@ -0,0 +1,25 @@ +package topic + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestDefaultTopic(t *testing.T) { + topic := New(nil) + require.Equal(t, "/", topic.Render()) +} + +func TestTopic(t *testing.T) { + expectedTopic := "/example/topic" + topic := New(nil, func(t *Topic) { + t.Topic = expectedTopic + }) + + require.Equal(t, expectedTopic, topic.Render()) +} diff --git a/samples/krill/components/tracer/service.go b/samples/krill/components/tracer/service.go new file mode 100644 index 0000000..c878640 --- /dev/null +++ b/samples/krill/components/tracer/service.go @@ -0,0 +1,54 @@ +package tracer + +import ( + "github.com/iot-for-all/device-simulation/components/observer" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/iot-for-all/device-simulation/lib/logger" +) + +type Store component.Store[Tracer, component.ID] + +type Component struct { + RegistryID component.ID +} + +type Service struct { + Store + registryStore registry.Store + Logger logger.Logger +} + +func NewStore() Store { + return component.New[Tracer, component.ID]() +} + +func NewService(store Store, registryStore registry.Store, options ...func(*Service)) *Service { + service := &Service{ + Store: store, + registryStore: registryStore, + Logger: &logger.NoopLogger{}, + } + + for _, option := range options { + option(service) + } + + return service +} + +func (service *Service) Create(id component.ID, c *Component) error { + var reg registry.Observable + reg, err := service.registryStore.Get(c.RegistryID) + if err != nil { + _, ok := err.(*component.NotFoundError) + if !ok { + return err + } + reg = &observer.NoopObservable{} + } + + return service.Store.Create(New(reg, func(bt *BlockingTracer) { + bt.Logger = service.Logger + }), id) +} diff --git a/samples/krill/components/tracer/service_test.go b/samples/krill/components/tracer/service_test.go new file mode 100644 index 0000000..d9871b6 --- /dev/null +++ b/samples/krill/components/tracer/service_test.go @@ -0,0 +1,76 @@ +package tracer + +import ( + "testing" + + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/iot-for-all/device-simulation/lib/logger" + "github.com/stretchr/testify/require" +) + +const ( + MockID = "MockID" + MockRegistryID = "MockRegistryID" +) + +func TestStore(t *testing.T) { + store := NewStore() + _, ok := store.(*component.Memstore[Tracer, component.ID]) + require.True(t, ok) +} + +func TestTracerService(t *testing.T) { + service := NewService(&component.MockStore[Tracer, component.ID]{ + OnCreate: func(entity Tracer, identifier component.ID) error { + require.Equal(t, MockID, string(identifier)) + return nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + require.Equal(t, MockRegistryID, string(identifier)) + return nil, nil + }, + }, func(s *Service) { + s.Logger = &logger.NoopLogger{} + }) + + err := service.Create(MockID, &Component{ + RegistryID: MockRegistryID, + }) + require.NoError(t, err) +} + +func TestTracerServiceNoopRegistry(t *testing.T) { + service := NewService(&component.MockStore[Tracer, component.ID]{ + OnCreate: func(entity Tracer, identifier component.ID) error { + require.Equal(t, MockID, string(identifier)) + return nil + }, + }, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + require.Equal(t, MockRegistryID, string(identifier)) + return nil, &component.NotFoundError{} + }, + }, func(s *Service) { + s.Logger = &logger.NoopLogger{} + }) + + err := service.Create(MockID, &Component{ + RegistryID: MockRegistryID, + }) + require.NoError(t, err) +} + +func TestTracerServiceRegistryError(t *testing.T) { + service := NewService(nil, &component.MockStore[registry.ObservableRegistry, component.ID]{ + OnGet: func(identifier component.ID) (registry.ObservableRegistry, error) { + return nil, &component.MockError{} + }, + }, func(s *Service) { + s.Logger = &logger.NoopLogger{} + }) + + err := service.Create(MockID, &Component{}) + require.Equal(t, &component.MockError{}, err) +} diff --git a/samples/krill/components/tracer/tracer.go b/samples/krill/components/tracer/tracer.go new file mode 100644 index 0000000..5ad3054 --- /dev/null +++ b/samples/krill/components/tracer/tracer.go @@ -0,0 +1,71 @@ +package tracer + +import ( + "fmt" + "time" + + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/lib/logger" +) + +type Tracer interface { + Begin() chan struct{} + Received() +} + +type BlockingTracer struct { + traces chan struct{} + times chan time.Time + reg registry.Observable + Logger logger.Logger + Trace logger.Logger +} + +func New(reg registry.Observable, options ...func(*BlockingTracer)) *BlockingTracer { + tracer := &BlockingTracer{ + reg: reg, + traces: make(chan struct{}), + times: make(chan time.Time, 1), + Logger: &logger.NoopLogger{}, + } + + for _, option := range options { + option(tracer) + } + + tracer.Trace = tracer.Logger.Level(logger.Trace) + + return tracer +} + +func (tracer *BlockingTracer) Begin() chan struct{} { + tracer.Trace.Printf("beginning trace") + tracer.times <- time.Now() + return tracer.traces +} + +func (tracer *BlockingTracer) Received() { + start := <-tracer.times + duration := float64(time.Since(start).Milliseconds()) + tracer.Trace.With("duration", fmt.Sprintf("%0.2f", duration)).Printf("ending trace") + tracer.reg.Observe(duration) + tracer.traces <- struct{}{} +} + +type NoopTracer struct { + c chan struct{} +} + +func NewNoopTracer() *NoopTracer { + c := make(chan struct{}) + close(c) + return &NoopTracer{ + c: c, + } +} + +func (tracer *NoopTracer) Begin() chan struct{} { + return tracer.c +} + +func (tracer *NoopTracer) Received() {} diff --git a/samples/krill/components/tracer/tracer_test.go b/samples/krill/components/tracer/tracer_test.go new file mode 100644 index 0000000..6117d6d --- /dev/null +++ b/samples/krill/components/tracer/tracer_test.go @@ -0,0 +1,46 @@ +package tracer + +import ( + "testing" + "time" + + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/lib/logger" + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestBlockingTracer(t *testing.T) { + waitMs := 5 + done := make(chan struct{}, 1) + tracer := New(®istry.MockObservable{ + OnObserve: func(val float64) { + // Ensure we were blocked for at least waitMs. + require.GreaterOrEqual(t, int(val), waitMs) + done <- struct{}{} + }, + }, func(bt *BlockingTracer) { + bt.Logger = &logger.NoopLogger{} + }) + + first := tracer.Begin() + go func() { + <-first + done <- struct{}{} + }() + // Block for several milliseconds + <-time.After(time.Millisecond * time.Duration(waitMs)) + tracer.Received() + + <-done + <-done +} + +func TestNoopTracer(t *testing.T) { + tracer := NewNoopTracer() + tracer.Received() + <-tracer.Begin() +} diff --git a/samples/krill/configs/simple/config.yml b/samples/krill/configs/simple/config.yml new file mode 100644 index 0000000..5e38662 --- /dev/null +++ b/samples/krill/configs/simple/config.yml @@ -0,0 +1,22 @@ +metrics: + type: prometheus + port: 2114 +logLevel: 1 +simulation: + target: + host: localhost + port: 1883 + sites: + - name: site0 + mqttVersion: v5 + assetCount: 3 + tags: + - id: float_1 + configuration: x + count: 1 + rate: + messagesPerPeriod: 2 + periodSeconds: 1 + tagsPerMessage: 2 + payloadFormat: OPCUA + topicFormat: /{{.SiteName}}/{{.AssetName}} diff --git a/samples/krill/go.mod b/samples/krill/go.mod new file mode 100644 index 0000000..84f25e5 --- /dev/null +++ b/samples/krill/go.mod @@ -0,0 +1,51 @@ +module github.com/iot-for-all/device-simulation + +go 1.20 + +require ( + github.com/eclipse/paho.golang v0.11.0 + github.com/eclipse/paho.mqtt.golang v1.4.2 + github.com/gofiber/fiber/v2 v2.42.0 + github.com/magefile/mage v1.15.0 + github.com/princjef/mageutil v1.0.0 + github.com/prometheus/client_golang v1.14.0 + github.com/rs/zerolog v1.29.0 + github.com/stretchr/testify v1.8.2 + google.golang.org/protobuf v1.29.1 + gopkg.in/yaml.v3 v3.0.1 +) + +require ( + github.com/VividCortex/ewma v1.2.0 // indirect + github.com/andybalholm/brotli v1.0.5 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cheggaaa/pb/v3 v3.1.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fatih/color v1.15.0 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/klauspost/compress v1.16.0 // indirect + github.com/kr/pretty v0.3.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.18 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/philhofer/fwd v1.1.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/procfs v0.9.0 // indirect + github.com/rivo/uniseg v0.4.4 // indirect + github.com/rogpeppe/go-internal v1.8.0 // indirect + github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect + github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect + github.com/tinylib/msgp v1.1.8 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.44.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sync v0.1.0 // indirect + golang.org/x/sys v0.8.0 // indirect +) diff --git a/samples/krill/go.sum b/samples/krill/go.sum new file mode 100644 index 0000000..f7d3b9a --- /dev/null +++ b/samples/krill/go.sum @@ -0,0 +1,207 @@ +github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= +github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= +github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheggaaa/pb v2.0.7+incompatible/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= +github.com/cheggaaa/pb/v3 v3.0.4/go.mod h1:7rgWxLrAUcFMkvJuv09+DYi7mMUYi8nO9iOWcvGJPfw= +github.com/cheggaaa/pb/v3 v3.1.2 h1:FIxT3ZjOj9XJl0U4o2XbEhjFfZl7jCVCDOGq1ZAB7wQ= +github.com/cheggaaa/pb/v3 v3.1.2/go.mod h1:SNjnd0yKcW+kw0brSusraeDd5Bf1zBfxAzTL2ss3yQ4= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/eclipse/paho.golang v0.11.0 h1:6Avu5dkkCfcB61/y1vx+XrPQ0oAl4TPYtY0uw3HbQdM= +github.com/eclipse/paho.golang v0.11.0/go.mod h1:rhrV37IEwauUyx8FHrvmXOKo+QRKng5ncoN1vJiJMcs= +github.com/eclipse/paho.mqtt.golang v1.4.2 h1:66wOzfUHSSI1zamx7jR6yMEI5EuHnT1G6rNA5PM12m4= +github.com/eclipse/paho.mqtt.golang v1.4.2/go.mod h1:JGt0RsEwEX+Xa/agj90YJ9d9DH2b7upDZMK9HRbFvCA= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofiber/fiber/v2 v2.42.0 h1:Fnp7ybWvS+sjNQsFvkhf4G8OhXswvB6Vee8hM/LyS+8= +github.com/gofiber/fiber/v2 v2.42.0/go.mod h1:3+SGNjqMh5VQH5Vz2Wdi43zTIV16ktlFd3x3R6O1Zlc= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= +github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= +github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/matryer/is v1.3.0 h1:9qiso3jaJrOe6qBRJRBt2Ldht05qDiFP9le0JOIhRSI= +github.com/matryer/is v1.3.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= +github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= +github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= +github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/princjef/mageutil v1.0.0 h1:1OfZcJUMsooPqieOz2ooLjI+uHUo618pdaJsbCXcFjQ= +github.com/princjef/mageutil v1.0.0/go.mod h1:mkShhaUomCYfAoVvTKRcbAs8YSVPdtezI5j6K+VXhrs= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w= +github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= +github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4= +github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94/go.mod h1:90zrgN3D/WJsDd1iXHT96alCoN2KJo6/4x1DZC3wZs8= +github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4= +github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk= +github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw= +github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= +github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.44.0 h1:R+gLUhldIsfg1HokMuQjdQ5bh9nuXHPIfvkYUu9eR5Q= +github.com/valyala/fasthttp v1.44.0/go.mod h1:f6VbjjoI3z1NDOZOv17o6RvtRSWxC77seBFc2uWtgiY= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.29.1 h1:7QBf+IK2gx70Ap/hDsOmam3GE0v9HicjfEdAxE62UoM= +google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/VividCortex/ewma.v1 v1.1.1/go.mod h1:TekXuFipeiHWiAlO1+wSS23vTcyFau5u3rxXUSXj710= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/cheggaaa/pb.v2 v2.0.7/go.mod h1:0CiZ1p8pvtxBlQpLXkHuUTpdJ1shm3OqCF1QugkjHL4= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fatih/color.v1 v1.7.0/go.mod h1:P7yosIhqIl/sX8J8UypY5M+dDpD2KmyfP5IRs5v/fo0= +gopkg.in/mattn/go-colorable.v0 v0.1.0/go.mod h1:BVJlBXzARQxdi3nZo6f6bnl5yR20/tOL6p+V0KejgSY= +gopkg.in/mattn/go-isatty.v0 v0.0.4/go.mod h1:wt691ab7g0X4ilKZNmMII3egK0bTxl37fEn/Fwbd8gc= +gopkg.in/mattn/go-runewidth.v0 v0.0.4/go.mod h1:BmXejnxvhwdaATwiJbB1vZ2dtXkQKZGu9yLFCZb4msQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/samples/krill/lib/binary/binary.go b/samples/krill/lib/binary/binary.go new file mode 100644 index 0000000..e675fc6 --- /dev/null +++ b/samples/krill/lib/binary/binary.go @@ -0,0 +1,64 @@ +package binary + +import ( + "encoding/binary" + "errors" + "math" + "time" +) + +type Encoder interface { + Encode(a any) ([]byte, error) +} + +type BinaryEncoder struct { + endian binary.ByteOrder +} + +func New(endian binary.ByteOrder) *BinaryEncoder { + return &BinaryEncoder{ + endian: endian, + } +} + +var ( + ErrInvalidFormatType = errors.New("cannot format this type into binary") +) + +func (encoder *BinaryEncoder) Encode(a any) ([]byte, error) { + var bts []byte + switch element := a.(type) { + case float64: + var buffer [8]byte + encoder.endian.PutUint64(buffer[:], math.Float64bits(element)) + bts = append(bts, buffer[:]...) + case int: + var buffer [4]byte + encoder.endian.PutUint32(buffer[:], uint32(element)) + bts = append(bts, buffer[:]...) + case string: + bts = append(bts, []byte(element)...) + case time.Time: + bts = append(bts, []byte(element.String())...) + case []any: + for _, elem := range element { + res, err := encoder.Encode(elem) + if err != nil { + return nil, err + } + bts = append(bts, res...) + } + default: + return nil, ErrInvalidFormatType + } + + return bts, nil +} + +type MockEncoder struct { + OnEncode func(a any) ([]byte, error) +} + +func (encoder *MockEncoder) Encode(a any) ([]byte, error) { + return encoder.OnEncode(a) +} diff --git a/samples/krill/lib/binary/binary_test.go b/samples/krill/lib/binary/binary_test.go new file mode 100644 index 0000000..8d8eed5 --- /dev/null +++ b/samples/krill/lib/binary/binary_test.go @@ -0,0 +1,77 @@ +package binary + +import ( + "encoding/binary" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestBinaryEncoderInt(t *testing.T) { + encoder := New(binary.BigEndian) + bts := make([]byte, 4) + res, err := encoder.Encode(0) + require.NoError(t, err) + require.Equal(t, bts, res) +} + +func TestBinaryEncoderFloat(t *testing.T) { + encoder := New(binary.BigEndian) + bts := make([]byte, 8) + res, err := encoder.Encode(0.0) + require.NoError(t, err) + require.Equal(t, bts, res) +} + +func TestBinaryEncoderString(t *testing.T) { + encoder := New(binary.BigEndian) + bts := []byte{0x41} + res, err := encoder.Encode("A") + require.NoError(t, err) + require.Equal(t, bts, res) +} + +func TestBinaryEncoderTime(t *testing.T) { + encoder := New(binary.BigEndian) + _, err := encoder.Encode(time.Now()) + require.NoError(t, err) +} + +func TestBinaryEncoderArray(t *testing.T) { + encoder := New(binary.BigEndian) + bts := make([]byte, 12) + res, err := encoder.Encode([]any{0, 0.0}) + require.NoError(t, err) + require.Equal(t, bts, res) +} + +func TestBinaryEncoderInvalidType(t *testing.T) { + encoder := New(binary.BigEndian) + type invalid int + _, err := encoder.Encode(invalid(1)) + require.Equal(t, ErrInvalidFormatType, err) +} + +func TestBinaryEncoderInvalidTypeWithinArray(t *testing.T) { + encoder := New(binary.BigEndian) + type invalid int + _, err := encoder.Encode([]any{invalid(1)}) + require.Equal(t, ErrInvalidFormatType, err) +} + +func TestMockEncoder(t *testing.T) { + encoder := &MockEncoder{ + OnEncode: func(a any) ([]byte, error) { + require.Nil(t, a) + return nil, nil + }, + } + + _, err := encoder.Encode(nil) + require.NoError(t, err) +} \ No newline at end of file diff --git a/samples/krill/lib/component/component.go b/samples/krill/lib/component/component.go new file mode 100644 index 0000000..42f3408 --- /dev/null +++ b/samples/krill/lib/component/component.go @@ -0,0 +1,19 @@ +package component + +type ( + ID string +) + +type ( + Store[E any, I comparable] interface { + Create(entity E, identifier I) error + Get(identifier I) (E, error) + Check(identifier I) error + Delete(identifier I) error + List() ([]I, error) + } + + Service[E any, I comparable] interface { + Create(identifier I, entity E) error + } +) \ No newline at end of file diff --git a/samples/krill/lib/component/component_test.go b/samples/krill/lib/component/component_test.go new file mode 100644 index 0000000..faca3dc --- /dev/null +++ b/samples/krill/lib/component/component_test.go @@ -0,0 +1,73 @@ +package component + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +const ( + NotFoundErrorMessage = "not found" + MockErrorMessage = "mock" +) + +func TestNotFoundError(t *testing.T) { + err := &NotFoundError{} + require.Equal(t, NotFoundErrorMessage, err.Error()) +} + +func TestMockService(t *testing.T) { + service := &MockService[struct{}, int]{ + OnCreate: func(identifier int, entity struct{}) error { + require.Equal(t, 0, identifier) + require.Equal(t, struct{}{}, entity) + return nil + }, + } + require.NoError(t, service.Create(0, struct{}{})) +} + +func TestMockStore(t *testing.T) { + store := &MockStore[struct{}, int]{ + OnCreate: func(entity struct{}, identifier int) error { + require.Equal(t, 0, identifier) + require.Equal(t, struct{}{}, entity) + return nil + }, + OnGet: func(identifier int) (struct{}, error) { + require.Equal(t, 0, identifier) + return struct{}{}, nil + }, + OnCheck: func(identifier int) error { + require.Equal(t, 0, identifier) + return nil + }, + OnDelete: func(identifier int) error { + require.Equal(t, 0, identifier) + return nil + }, + OnList: func() ([]int, error) { + return nil, nil + }, + } + + require.NoError(t, store.Create(struct{}{}, 0)) + require.NoError(t, store.Check(0)) + require.NoError(t, store.Delete(0)) + + _, err := store.Get(0) + require.NoError(t, err) + + _, err = store.List() + require.NoError(t, err) +} + +func TestMockError(t *testing.T) { + err := &MockError{ + OnError: func() string { + return MockErrorMessage + }, + } + + require.Equal(t, MockErrorMessage, err.Error()) +} \ No newline at end of file diff --git a/samples/krill/lib/component/errors.go b/samples/krill/lib/component/errors.go new file mode 100644 index 0000000..5b1c083 --- /dev/null +++ b/samples/krill/lib/component/errors.go @@ -0,0 +1,7 @@ +package component + +type NotFoundError struct {} + +func (err *NotFoundError) Error() string { + return "not found" +} \ No newline at end of file diff --git a/samples/krill/lib/component/mock.go b/samples/krill/lib/component/mock.go new file mode 100644 index 0000000..d054733 --- /dev/null +++ b/samples/krill/lib/component/mock.go @@ -0,0 +1,46 @@ +package component + +type ( + MockService[E any, I comparable] struct { + OnCreate func(identifier I, entity E) error + } + MockStore[E any, I comparable] struct { + OnCreate func(entity E, identifier I) error + OnGet func(identifier I) (E, error) + OnCheck func(identifier I) error + OnDelete func(identifier I) error + OnList func() ([]I, error) + } +) + +func (service *MockService[E, I]) Create(identifier I, entity E) error { + return service.OnCreate(identifier, entity) +} + +func (store *MockStore[E, I]) Create(entity E, identifier I) error { + return store.OnCreate(entity, identifier) +} + +func (store *MockStore[E, I]) Get(identifier I) (E, error) { + return store.OnGet(identifier) +} + +func (store *MockStore[E, I]) Check(identifier I) error { + return store.OnCheck(identifier) +} + +func (store *MockStore[E, I]) Delete(identifier I) error { + return store.OnDelete(identifier) +} + +func (store *MockStore[E, I]) List() ([]I, error) { + return store.OnList() +} + +type MockError struct { + OnError func() string +} + +func (err *MockError) Error() string { + return err.OnError() +} diff --git a/samples/krill/lib/component/store.go b/samples/krill/lib/component/store.go new file mode 100644 index 0000000..04d9081 --- /dev/null +++ b/samples/krill/lib/component/store.go @@ -0,0 +1,77 @@ +package component + +import ( + "sync" +) + +type StoreOption[E any, I comparable] func(*Memstore[E, I]) + +type Memstore[E any, I comparable] struct { + memory map[I]E + mu *sync.RWMutex +} + +func New[E any, I comparable]() *Memstore[E, I] { + store := &Memstore[E, I]{ + memory: make(map[I]E), + mu: &sync.RWMutex{}, + } + + return store +} + +func (memstore *Memstore[E, I]) Create(entity E, identifier I) error { + + memstore.mu.Lock() + memstore.memory[identifier] = entity + memstore.mu.Unlock() + + return nil +} + +func (memstore *Memstore[E, I]) Get(identifier I) (E, error) { + var entity E + + memstore.mu.RLock() + entity, ok := memstore.memory[identifier] + memstore.mu.RUnlock() + + if ok { + return entity, nil + } + return entity, &NotFoundError{} +} + +func (memstore *Memstore[E, I]) Check(identifier I) error { + memstore.mu.RLock() + _, ok := memstore.memory[identifier] + memstore.mu.RUnlock() + + if ok { + return nil + } + return &NotFoundError{} +} + +func (memstore *Memstore[E, I]) Delete(identifier I) error { + + memstore.mu.Lock() + delete(memstore.memory, identifier) + memstore.mu.Unlock() + return nil +} + +func (memstore *Memstore[E, I]) List() ([]I, error) { + keys := make([]I, len(memstore.memory)) + + index := 0 + + memstore.mu.RLock() + for k := range memstore.memory { + keys[index] = k + index++ + } + memstore.mu.RUnlock() + + return keys, nil +} diff --git a/samples/krill/lib/component/store_test.go b/samples/krill/lib/component/store_test.go new file mode 100644 index 0000000..469d447 --- /dev/null +++ b/samples/krill/lib/component/store_test.go @@ -0,0 +1,71 @@ +package component + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +var ( + keyOne = "1" + valueOne = 1 + keyTwo = "2" + valueTwo = 2 +) + +func TestCreate(t *testing.T) { + store := New[int, string]() + err := store.Create(valueOne, keyOne) + require.NoError(t, err) +} + +func TestGet(t *testing.T) { + store := New[int, string]() + err := store.Create(valueOne, keyOne) + require.NoError(t, err) + v, err := store.Get(keyOne) + require.NoError(t, err) + require.Equal(t, valueOne, v) +} + +func TestDelete(t *testing.T) { + store := New[int, string]() + err := store.Delete(keyOne) + require.NoError(t, err) + err = store.Create(valueOne, keyOne) + require.NoError(t, err) + v, err := store.Get(keyOne) + require.NoError(t, err) + require.Equal(t, valueOne, v) + err = store.Delete(keyOne) + require.NoError(t, err) + _, err = store.Get(keyOne) + require.Equal(t, &NotFoundError{}, err) +} + +func TestList(t *testing.T) { + store := New[int, string]() + _, err := store.List() + require.NoError(t, err) + err = store.Create(valueOne, keyOne) + require.NoError(t, err) + err = store.Create(valueTwo, keyTwo) + require.NoError(t, err) + vals, err := store.List() + require.NoError(t, err) + require.ElementsMatch(t, []string{keyOne, keyTwo}, vals) +} + +func TestCheck(t *testing.T) { + store := New[int, string]() + err := store.Check(keyOne) + require.Equal(t, &NotFoundError{}, err) + err = store.Create(valueOne, keyOne) + require.NoError(t, err) + err = store.Check(keyOne) + require.NoError(t, err) +} diff --git a/samples/krill/lib/composition/composition.go b/samples/krill/lib/composition/composition.go new file mode 100644 index 0000000..1924386 --- /dev/null +++ b/samples/krill/lib/composition/composition.go @@ -0,0 +1,179 @@ +package composition + +import ( + "sort" + + "github.com/iot-for-all/device-simulation/lib/expression" + "github.com/iot-for-all/device-simulation/lib/logger" +) + +const ( + ExpressionErrorMessage = "an error occurred while evaluating the expression leaf" +) + +type Renderer interface { + Render(map[string]any) any +} + +type Node interface { + Renderer + With(Edge) Node +} + +type Edge interface { + Renderer + Edge() any +} + +// Edge implementations. +type Label struct { + label string + value Renderer +} + +func NewLabel(label string, value Renderer) *Label { + return &Label{ + label: label, + value: value, + } +} + +func (label *Label) Render(env map[string]any) any { + return label.value.Render(env) +} + +func (label *Label) Edge() any { + return label.label +} + +type Position struct { + position int + value Renderer +} + +func NewPosition(position int, value Renderer) *Position { + return &Position{ + position: position, + value: value, + } +} + +func (position *Position) Render(env map[string]any) any { + return position.value.Render(env) +} + +func (position *Position) Edge() any { + return position.position +} + +// Node implementations. +type Collection struct { + labels []*Label +} + +func NewCollection() *Collection { + return &Collection{} +} + +func (collection *Collection) With(e Edge) Node { + collection.labels = append(collection.labels, e.(*Label)) + return collection +} + +func (collection *Collection) Render(env map[string]any) any { + m := make(map[string]any) + for _, label := range collection.labels { + switch r := label.Render(env).(type) { + case Renderer: + m[label.Edge().(string)] = r.Render(env) + default: + m[label.Edge().(string)] = r + } + } + return m +} + +type ArrayPositions []*Position + +func (a ArrayPositions) Len() int { + return len(a) +} + +func (a ArrayPositions) Swap(i int, j int) { + a[i], a[j] = a[j], a[i] +} + +func (a ArrayPositions) Less(i int, j int) bool { + return a[i].Edge().(int) < a[j].Edge().(int) +} + +type Array struct { + Positions ArrayPositions +} + +func NewArray() *Array { + return &Array{} +} + +func (array *Array) With(e Edge) Node { + array.Positions = append(array.Positions, e.(*Position)) + return array +} + +func (array *Array) Render(env map[string]any) any { + a := make([]any, len(array.Positions)) + + sort.Sort(array.Positions) + + for idx, position := range array.Positions { + a[idx] = position.Render(env) + } + + return a +} + +// Renderer implementations. +type Expression struct { + Logger logger.Logger + evaluator expression.Evaluator +} + +func NewExpression( + evaluator expression.Evaluator, + options ...func(*Expression), +) *Expression { + expr := &Expression{ + evaluator: evaluator, + Logger: &logger.NoopLogger{}, + } + + for _, option := range options { + option(expr) + } + + return expr +} + +func (expr *Expression) Render(ctx map[string]any) any { + v, err := expr.evaluator.Evaluate(ctx) + if err != nil { + expr.Logger.Level(logger.Error). + With("error", err.Error()). + Printf(ExpressionErrorMessage) + } + return v +} + +type Static struct { + value any +} + +func NewStatic(value any) *Static { + return &Static{ + value: value, + } +} + +func (stat *Static) Render(map[string]any) any { + return stat.value +} diff --git a/samples/krill/lib/composition/composition_test.go b/samples/krill/lib/composition/composition_test.go new file mode 100644 index 0000000..cb6b235 --- /dev/null +++ b/samples/krill/lib/composition/composition_test.go @@ -0,0 +1,128 @@ +package composition + +import ( + "errors" + "testing" + + "github.com/iot-for-all/device-simulation/lib/expression" + "github.com/iot-for-all/device-simulation/lib/logger" + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestLabelCollectionPositionAndStatic(t *testing.T) { + expected := map[string]any{ + "my-label": map[string]any{ + "my-array": []any{5, 6}, + }, + } + + val := NewCollection().With( + NewLabel("my-label", NewCollection().With( + NewLabel("my-array", NewArray().With( + NewPosition(5, NewStatic(5)), + ).With( + NewPosition(6, NewStatic(6)), + )), + )), + ).Render(nil) + + require.Equal(t, expected, val) +} + +func TestExpression(t *testing.T) { + expected := 1 + expr := NewExpression(&expression.MockEvaluator{ + OnEvaluate: func(m map[string]any) (any, error) { + return expected, nil + }, + }, func(e *Expression) { + e.Logger = &logger.MockLogger{ + OnPrintf: func(s string, i ...interface{}) { + require.Equal(t, ExpressionErrorMessage, s) + }, OnLevel: func(i int) logger.Logger { + require.Equal(t, logger.Error, i) + return e.Logger + }, OnWith: func(s1, s2 string) logger.Logger { + return e.Logger + }, + } + }) + + res := expr.Render(nil) + require.Equal(t, expected, res) +} + +func TestExpressionErrorLog(t *testing.T) { + errMock := errors.New("mock error") + expr := NewExpression(&expression.MockEvaluator{ + OnEvaluate: func(m map[string]any) (any, error) { + return nil, errMock + }, + }, func(e *Expression) { + e.Logger = &logger.MockLogger{ + OnPrintf: func(s string, i ...interface{}) { + require.Equal(t, ExpressionErrorMessage, s) + }, OnLevel: func(i int) logger.Logger { + require.Equal(t, logger.Error, i) + return e.Logger + }, OnWith: func(s1, s2 string) logger.Logger { + require.Equal(t, errMock.Error(), s2) + return e.Logger + }, + } + }) + + expr.Render(nil) +} + +func TestSwapArrayPositions(t *testing.T) { + pos := ArrayPositions{ + { + position: 0, + }, + { + position: 1, + }, + } + + pos.Swap(0, 1) + + require.Equal(t, 1, pos[0].position) + require.Equal(t, 0, pos[1].position) +} + +func TestMockRenderer(t *testing.T) { + renderer := &MockRenderer{ + OnRender: func(m map[string]any) any { + require.Nil(t, m) + return nil + }, + } + + require.Nil(t, renderer.Render(nil)) +} + +func TestMockEdge(t *testing.T) { + edge := &MockEdge{ + OnEdge: func() any { + return nil + }, + } + + require.Nil(t, edge.Edge()) +} + +func TestMockNode(t *testing.T) { + node := &MockNode{ + OnWith: func(e Edge) Node { + require.Equal(t, &MockEdge{}, e) + return &MockNode{} + }, + } + + require.Equal(t, &MockNode{}, node.With(&MockEdge{})) +} \ No newline at end of file diff --git a/samples/krill/lib/composition/mock.go b/samples/krill/lib/composition/mock.go new file mode 100644 index 0000000..02cb074 --- /dev/null +++ b/samples/krill/lib/composition/mock.go @@ -0,0 +1,27 @@ +package composition + +type MockRenderer struct { + OnRender func(map[string]any) any +} + +func (renderer *MockRenderer) Render(m map[string]any) any { + return renderer.OnRender(m) +} + +type MockEdge struct { + Renderer + OnEdge func() any +} + +func (edge *MockEdge) Edge() any { + return edge.OnEdge() +} + +type MockNode struct { + Renderer + OnWith func(Edge) Node +} + +func (node *MockNode) With(e Edge) Node { + return node.OnWith(e) +} \ No newline at end of file diff --git a/samples/krill/lib/counter/counter.go b/samples/krill/lib/counter/counter.go new file mode 100644 index 0000000..5278659 --- /dev/null +++ b/samples/krill/lib/counter/counter.go @@ -0,0 +1,145 @@ +// Package counter contains the counter-based implementations of a Provider. +// Counter Providers represent and wrap the counterVec prometheus metrics. +package counter + +import ( + "fmt" + + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/lib/errors" + + "github.com/prometheus/client_golang/prometheus" +) + +// Provider is an implementation of the registry.Provider interface. +// Its purpose is to register a new prometheus counterVec when created, +// And to create a counter (a prometheus counter with a provided label) when its with function is called. +type Provider struct { + CounterVec *prometheus.CounterVec + registry prometheus.Registerer + Name string + Help string + Label string +} + +const ( + SimulationCounterDefaultName = "simulation_counter" + SimulationCounterDefaultHelp = "Simulation counter" + CounterLabelKey = "counter" +) + +type InvalidPrometheusCounterVecNameError struct { + errors.BadRequest + name string +} + +func (err *InvalidPrometheusCounterVecNameError) Error() string { + return fmt.Sprintf( + "could not create the counter provider with the name %s because the name has already been registered or is invalid", + err.name, + ) +} + +type InvalidPrometheusCounterLabelError struct { + errors.BadRequest + name string + label string +} + +func (err *InvalidPrometheusCounterLabelError) Error() string { + return fmt.Sprintf( + "could not create the prometheus counter with label %s from counter provider %s because the label has already been used or is invalid", + err.label, + err.name, + ) +} + +// New creates a Provider given a prometheus registerer. +// It can also take a function to set optional parameters. +func New( + reg prometheus.Registerer, + options ...func(*Provider), +) (*Provider, error) { + counterProvider := &Provider{ + Name: SimulationCounterDefaultName, + Help: SimulationCounterDefaultHelp, + Label: CounterLabelKey, + registry: reg, + } + + for _, option := range options { + option(counterProvider) + } + + counterProvider.CounterVec = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: counterProvider.Name, + Help: counterProvider.Help, + }, + []string{counterProvider.Label}, + ) + + err := counterProvider.registry.Register(counterProvider.CounterVec) + + if err != nil { + return nil, &InvalidPrometheusCounterVecNameError{ + name: counterProvider.Name, + } + } + + return counterProvider, nil +} + +// Cancel unregisters the prometheus counterVec from the prometheus registerer. +func (counterProvider *Provider) Cancel() error { + counterProvider.registry.Unregister(counterProvider.CounterVec) + return nil +} + +// With attempts to create a Counter, which is a wrapper around the prometheus counter metric that implements the CancellableObservable interface. +// It returns an error if a failure is encountered. +func (counterProvider *Provider) With( + label string, +) (registry.CancellableObservable, error) { + + counter, err := counterProvider.CounterVec.GetMetricWith( + prometheus.Labels{counterProvider.Label: label}, + ) + + if err != nil { + return nil, &InvalidPrometheusCounterLabelError{ + name: counterProvider.Name, + label: label, + } + } + + return NewCounter(counterProvider.registry, counter), nil +} + +// Counter is an implementation of CancellableObservable which wraps the functionality of the prometheus counter metric. +// It increments the counter when its observe function is called. +type Counter struct { + observable prometheus.Counter + registry prometheus.Registerer +} + +// NewCounter creates a Counter given a prometheus counter and a prometheus registerer. +func NewCounter( + reg prometheus.Registerer, + observable prometheus.Counter, +) *Counter { + return &Counter{ + registry: reg, + observable: observable, + } +} + +// Cancel unregisters the prometheus counter from the registerer. +func (counter Counter) Cancel() { + counter.registry.Unregister(counter.observable) +} + +// Observe calls the increment function of the prometheus counter. +func (counter Counter) Observe(float64) { + counter.observable.Inc() +} \ No newline at end of file diff --git a/samples/krill/lib/counter/counter_test.go b/samples/krill/lib/counter/counter_test.go new file mode 100644 index 0000000..745b0ca --- /dev/null +++ b/samples/krill/lib/counter/counter_test.go @@ -0,0 +1,104 @@ +package counter + +import ( + "testing" + + "github.com/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +const ( + name = "name" + label = "label" + invalid = "{}|}][" + invalidUTF8 = "\xc3\x28" +) + +func TestSimpleCounterProvider(t *testing.T) { + registry := prometheus.NewRegistry() + + counterProvider, err := New(registry) + + require.NoError(t, err) + + counterProvider.Cancel() +} + +func TestCounterProviderWithInvalidName(t *testing.T) { + registry := prometheus.NewRegistry() + + _, err := New(registry, func(cp *Provider) { + cp.Name = invalid + }) + + require.Equal(t, &InvalidPrometheusCounterVecNameError{ + name: invalid, + }, err) +} + +func TestCounterProviderWithDuplicateNames(t *testing.T) { + + registry := prometheus.NewRegistry() + + counterProvider, err := New(registry, func(cp *Provider) { + cp.Name = name + }) + + require.NoError(t, err) + + _, err = counterProvider.With(label) + + require.NoError(t, err) + + _, err = New(registry, func(cp *Provider) { + cp.Name = name + }) + + require.Equal(t, (&InvalidPrometheusCounterVecNameError{ + name: name, + }).Error(), err.Error()) +} + +func TestCounterWithLabel(t *testing.T) { + + registry := prometheus.NewRegistry() + + counterProvider, err := New(registry, func(cp *Provider) { + cp.Name = name + }) + + require.NoError(t, err) + + counter, err := counterProvider.With(name) + + counter.Observe(0) + counter.Cancel() + + require.NoError(t, err) +} + +func TestCounterWithLabelError(t *testing.T) { + + registry := prometheus.NewRegistry() + + counterProvider, err := New(registry, func(cp *Provider) { + cp.Name = name + }) + + require.NoError(t, err) + + _, err = counterProvider.With("") + + require.NoError(t, err) + + _, err = counterProvider.With(invalidUTF8) + + require.Equal(t, (&InvalidPrometheusCounterLabelError{ + name: name, + label: invalidUTF8, + }).Error(), err.Error()) +} \ No newline at end of file diff --git a/samples/krill/lib/dialer/dialer.go b/samples/krill/lib/dialer/dialer.go new file mode 100644 index 0000000..6d7ca14 --- /dev/null +++ b/samples/krill/lib/dialer/dialer.go @@ -0,0 +1,147 @@ +// Package dialers defines interfaces for GRPC and TCP dialers which are used across various parts of the simulation framework. +// It also contains mock implementations for testing purposes and wrappers around the dial functions provided by the net and google grpc packages. +package dialer + +import ( + "net" + "time" +) + +// Dialer is an interface which describes the net package's dialer functionality. +type Dialer interface { + Dial(network string, address string) (net.Conn, error) +} + +// NetDialer is an implementation of Dialer which wraps the dial functionality of the net package dial function. +type NetDialer struct{ + OnDial func(network string, address string) (net.Conn, error) +} + +func New(options ...func(*NetDialer)) *NetDialer { + dialer := &NetDialer{ + OnDial: net.Dial, + } + + for _, option := range options { + option(dialer) + } + + return dialer +} + +// Dial calls the net package's dial function, passing through its network type and address parameters. +func (dialer *NetDialer) Dial(network string, address string) (net.Conn, error) { + return dialer.OnDial(network, address) +} + +type MockDialer struct { + OnDial func(network string, address string) (net.Conn, error) +} + +func (dialer *MockDialer) Dial(network string, address string) (net.Conn, error) { + return dialer.OnDial(network, address) +} + +type MockConn struct { + OnRead func(b []byte) (n int, err error) + OnWrite func(b []byte) (n int, err error) + OnClose func() error + OnLocalAddr func() net.Addr + OnRemoteAddr func() net.Addr + OnSetDeadline func(t time.Time) error + OnSetReadDeadline func(t time.Time) error + OnSetWriteDeadline func(t time.Time) error +} + +func (conn *MockConn) Read(b []byte) (n int, err error) { + return conn.OnRead(b) +} + +func (conn *MockConn) Write(b []byte) (n int, err error) { + return conn.OnWrite(b) +} + +func (conn *MockConn) Close() error { + return conn.OnClose() +} + +func (conn *MockConn) LocalAddr() net.Addr { + return conn.OnLocalAddr() +} + +func (conn *MockConn) RemoteAddr() net.Addr { + return conn.OnRemoteAddr() +} + +func (conn *MockConn) SetDeadline(t time.Time) error { + return conn.OnSetDeadline(t) +} + +func (conn *MockConn) SetReadDeadline(t time.Time) error { + return conn.OnSetReadDeadline(t) +} + +func (conn *MockConn) SetWriteDeadline(t time.Time) error { + return conn.OnSetWriteDeadline(t) +} + +type MockAddr struct { + OnNetwork func() string + OnString func() string +} + +func (addr *MockAddr) Network() string { + return addr.OnNetwork() +} + +func (addr *MockAddr) String() string { + return addr.OnString() +} + +type NoopConn struct { + +} + +func (*NoopConn) Read(b []byte) (n int, err error) { + return 0, nil +} + +func (*NoopConn) Write(b []byte) (n int, err error) { + return 0, nil +} + +func (*NoopConn) Close() error { + return nil +} + +func (*NoopConn) LocalAddr() net.Addr { + return &NoopAddr{} +} + +func (*NoopConn) RemoteAddr() net.Addr { + return &NoopAddr{} +} + +func (*NoopConn) SetDeadline(t time.Time) error { + return nil +} + +func (*NoopConn) SetReadDeadline(t time.Time) error { + return nil +} + +func (*NoopConn) SetWriteDeadline(t time.Time) error { + return nil +} + +type NoopAddr struct { + +} + +func (*NoopAddr) Network() string { + return "" +} + +func (*NoopAddr) String() string { + return "" +} \ No newline at end of file diff --git a/samples/krill/lib/dialer/dialer_test.go b/samples/krill/lib/dialer/dialer_test.go new file mode 100644 index 0000000..86b78e8 --- /dev/null +++ b/samples/krill/lib/dialer/dialer_test.go @@ -0,0 +1,121 @@ +package dialer + +import ( + "net" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +const ( + MockString = "MockString" + MockNetwork = "MockNetwork" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestMockConn(t *testing.T) { + conn := &MockConn{ + OnRead: func(b []byte) (int, error) { + return 0, nil + }, + OnWrite: func(b []byte) (int, error) { + return 0, nil + }, + OnClose: func() error { + return nil + }, + OnLocalAddr: func() net.Addr { + return nil + }, + OnRemoteAddr: func() net.Addr { + return nil + }, + OnSetDeadline: func(t time.Time) error { + return nil + }, + OnSetReadDeadline: func(t time.Time) error { + return nil + }, + OnSetWriteDeadline: func(t time.Time) error { + return nil + }, + } + + require.NoError(t, conn.Close()) + require.NoError(t, conn.SetDeadline(time.Now())) + require.NoError(t, conn.SetReadDeadline(time.Now())) + require.NoError(t, conn.SetWriteDeadline(time.Now())) + + _, err := conn.Read(nil) + require.NoError(t, err) + + _, err = conn.Write(nil) + require.NoError(t, err) + + require.Nil(t, conn.LocalAddr()) + require.Nil(t, conn.RemoteAddr()) +} + +func TestMockAddr(t *testing.T) { + addr := &MockAddr{ + OnNetwork: func() string { + return MockNetwork + }, OnString: func() string { + return MockString + }, + } + + require.Equal(t, MockString, addr.String()) + require.Equal(t, MockNetwork, addr.Network()) +} + +func TestNoopConn(t *testing.T) { + conn := &NoopConn{} + + require.NoError(t, conn.Close()) + require.NoError(t, conn.SetDeadline(time.Now())) + require.NoError(t, conn.SetReadDeadline(time.Now())) + require.NoError(t, conn.SetWriteDeadline(time.Now())) + + _, err := conn.Read(nil) + require.NoError(t, err) + + _, err = conn.Write(nil) + require.NoError(t, err) + + require.Equal(t, &NoopAddr{}, conn.LocalAddr()) + require.Equal(t, &NoopAddr{}, conn.RemoteAddr()) +} + +func TestNoopAddr(t *testing.T) { + addr := &NoopAddr{} + + require.Equal(t, "", addr.String()) + require.Equal(t, "", addr.Network()) +} + +func TestNetDialer(t *testing.T) { + dialer := New(func(nd *NetDialer) { + nd.OnDial = func(network, address string) (net.Conn, error) { + return nil, nil + } + }) + + _, err := dialer.Dial("", "") + require.NoError(t, err) +} + +func TestMockDialer(t *testing.T) { + dialer := &MockDialer{ + OnDial: func(network, address string) (net.Conn, error) { + return nil, nil + }, + } + + _, err := dialer.Dial("", "") + require.NoError(t, err) +} \ No newline at end of file diff --git a/samples/krill/lib/env/env.go b/samples/krill/lib/env/env.go new file mode 100644 index 0000000..a825aed --- /dev/null +++ b/samples/krill/lib/env/env.go @@ -0,0 +1,98 @@ +package env + +import ( + "flag" + "os" + "path" + + "gopkg.in/yaml.v3" +) + +type UnmarshalFunc func(data []byte, v any) error + +type ConfigurationReader[E any] struct { + ReadFile func(name string) ([]byte, error) + Unmarshal UnmarshalFunc +} + +func New[E any](options ...func(*ConfigurationReader[E])) *ConfigurationReader[E] { + reader := &ConfigurationReader[E]{ + ReadFile: os.ReadFile, + Unmarshal: yaml.Unmarshal, + } + + for _, option := range options { + option(reader) + } + + return reader +} + +func (reader *ConfigurationReader[E]) Read( + configSrc string, +) (E, error) { + var config E + + content, err := reader.ReadFile(path.Clean(configSrc)) + if err != nil { + return config, &CannotOpenConfigurationFileError{ + err: err, + } + } + + err = reader.Unmarshal(content, &config) + if err != nil { + return config, &CannotParseFileContentError{ + err: err, + } + } + + return config, err +} + +func ReadEnv(key string) string { + return os.Getenv(key) +} + +type FlagParser struct { + ParseInt func(name string, value int, usage string) *int + ParseString func(name string, value string, usage string) *string + ParseBool func(name string, value bool, usage string) *bool + Parse func() +} + +func NewFlagParser(options ...func(*FlagParser)) *FlagParser { + parser := &FlagParser{ + ParseInt: flag.Int, + ParseString: flag.String, + ParseBool: flag.Bool, + Parse: flag.Parse, + } + + for _, option := range options { + option(parser) + } + + return parser +} + +func (parser *FlagParser) ReadFlags(flags map[string]any) (map[string]any, error) { + m := make(map[string]any) + + for f, t := range flags { + switch def := t.(type) { + case int: + m[f] = parser.ParseInt(f, def, "") + case string: + m[f] = parser.ParseString(f, def, "") + case bool: + m[f] = parser.ParseBool(f, def, "") + default: + return nil, &InvalidFlagTypeError{} + } + } + + parser.Parse() + + return m, nil +} diff --git a/samples/krill/lib/env/env_test.go b/samples/krill/lib/env/env_test.go new file mode 100644 index 0000000..55a9186 --- /dev/null +++ b/samples/krill/lib/env/env_test.go @@ -0,0 +1,166 @@ +package env + +import ( + "flag" + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +const ( + MockSource = "MockSource" + MockConfigProperty = "MockConfig" + MockBoolFlagName = "MockBoolFlagName" + MockStringFlagName = "MockStringFlagName" + MockIntFlagName = "MockIntFlagName" + MockStringFlagDefault = "MockStringFlagDefault" + MockBoolFlagDefault = true + MockIntFlagDefault = 1 +) + +var ( + MockContent = []byte{0, 1} +) + +type MockError struct{} + +func (*MockError) Error() string { + return "mock" +} + +type MockConfig struct { + Property string +} + +var originalFlagSet flag.FlagSet + +func TestMain(m *testing.M) { + originalFlagSet = *flag.CommandLine + m.Run() +} + +func TestReadEnv(t *testing.T) { + v := "test" + err := os.Setenv(v, v) + require.NoError(t, err) + require.Equal(t, v, ReadEnv(v)) + ReadEnv(v) +} + +func TestConfigurationReader(t *testing.T) { + reader := New[MockConfig](func(cr *ConfigurationReader[MockConfig]) { + cr.Unmarshal = func(data []byte, v any) error { + require.Equal(t, MockContent, data) + res, ok := v.(*MockConfig) + require.True(t, ok) + res.Property = MockConfigProperty + return nil + } + cr.ReadFile = func(name string) ([]byte, error) { + require.Equal(t, MockSource, name) + return MockContent, nil + } + }) + + res, err := reader.Read(MockSource) + require.NoError(t, err) + require.Equal(t, MockConfigProperty, res.Property) +} + +func TestConfigurationReaderReadFileError(t *testing.T) { + reader := New[MockConfig](func(cr *ConfigurationReader[MockConfig]) { + cr.ReadFile = func(name string) ([]byte, error) { + return nil, &MockError{} + } + }) + + _, err := reader.Read(MockSource) + require.Equal(t, (&CannotOpenConfigurationFileError{ + err: &MockError{}, + }).Error(), err.Error()) +} + +func TestConfigurationReaderUnmarshalError(t *testing.T) { + reader := New[MockConfig](func(cr *ConfigurationReader[MockConfig]) { + cr.ReadFile = func(name string) ([]byte, error) { + return nil, nil + } + cr.Unmarshal = func(data []byte, v any) error { + return &MockError{} + } + }) + + _, err := reader.Read(MockSource) + require.Equal(t, (&CannotParseFileContentError{ + err: &MockError{}, + }).Error(), err.Error()) +} + +func TestFlagParserBool(t *testing.T) { + done := make(chan struct{}) + parser := NewFlagParser(func(fp *FlagParser) { + fp.Parse = func() { + close(done) + } + fp.ParseBool = func(name string, value bool, usage string) *bool { + require.Equal(t, "", usage) + require.Equal(t, MockBoolFlagName, name) + require.Equal(t, MockBoolFlagDefault, value) + return nil + } + }) + + m, err := parser.ReadFlags(map[string]any{ + MockBoolFlagName: MockBoolFlagDefault, + }) + require.NoError(t, err) + require.Nil(t, m[MockBoolFlagName]) + + <-done +} + +func TestFlagParserInt(t *testing.T) { + parser := NewFlagParser(func(fp *FlagParser) { + fp.Parse = func() {} + fp.ParseInt = func(name string, value int, usage string) *int { + require.Equal(t, "", usage) + require.Equal(t, MockIntFlagName, name) + require.Equal(t, MockIntFlagDefault, value) + return nil + } + }) + + m, err := parser.ReadFlags(map[string]any{ + MockIntFlagName: MockIntFlagDefault, + }) + require.NoError(t, err) + require.Nil(t, m[MockIntFlagName]) +} + +func TestFlagParserString(t *testing.T) { + parser := NewFlagParser(func(fp *FlagParser) { + fp.Parse = func() {} + fp.ParseString = func(name string, value string, usage string) *string { + require.Equal(t, "", usage) + require.Equal(t, MockStringFlagDefault, name) + require.Equal(t, MockStringFlagDefault, value) + return nil + } + }) + + m, err := parser.ReadFlags(map[string]any{ + MockStringFlagDefault: MockStringFlagDefault, + }) + require.NoError(t, err) + require.Nil(t, m[MockStringFlagDefault]) +} + +func TestInvalidFlagTypeError(t *testing.T) { + parser := NewFlagParser(func(fp *FlagParser) {}) + + _, err := parser.ReadFlags(map[string]any{ + "": nil, + }) + require.Equal(t, (&InvalidFlagTypeError{}).Error(), err.Error()) +} diff --git a/samples/krill/lib/env/errors.go b/samples/krill/lib/env/errors.go new file mode 100644 index 0000000..da7c868 --- /dev/null +++ b/samples/krill/lib/env/errors.go @@ -0,0 +1,25 @@ +package env + +import "fmt" + +type CannotOpenConfigurationFileError struct { + err error +} + +func (err *CannotOpenConfigurationFileError) Error() string { + return fmt.Sprintf("the file at the provided path could not be opened: %q", err.err.Error()) +} + +type CannotParseFileContentError struct { + err error +} + +func (err *CannotParseFileContentError) Error() string { + return fmt.Sprintf("the content of the specified file could not be parsed: %q", err.err.Error()) +} + +type InvalidFlagTypeError struct {} + +func (*InvalidFlagTypeError) Error() string { + return "flag default must be of type int, string, or bool" +} \ No newline at end of file diff --git a/samples/krill/lib/environment/environment.go b/samples/krill/lib/environment/environment.go new file mode 100644 index 0000000..6240a05 --- /dev/null +++ b/samples/krill/lib/environment/environment.go @@ -0,0 +1,46 @@ +package environment + +import "sync" + +type Environment interface { + Env() map[string]any + Set(string, any) +} + +type MapEnvironment struct { + env map[string]any + mu sync.RWMutex +} + +func New() *MapEnvironment { + return &MapEnvironment{ + env: make(map[string]any), + } +} + +func (env *MapEnvironment) Env() map[string]any { + env.mu.RLock() + defer env.mu.RUnlock() + + return env.env +} + +func (env *MapEnvironment) Set(s string, a any) { + env.mu.Lock() + defer env.mu.Unlock() + + env.env[s] = a +} + +type MockEnvironment struct { + OnEnv func() map[string]any + OnSet func(string, any) +} + +func (environment *MockEnvironment) Env() map[string]any { + return environment.OnEnv() +} + +func (environment *MockEnvironment) Set(s string, a any) { + environment.OnSet(s, a) +} diff --git a/samples/krill/lib/environment/environment_test.go b/samples/krill/lib/environment/environment_test.go new file mode 100644 index 0000000..ed88229 --- /dev/null +++ b/samples/krill/lib/environment/environment_test.go @@ -0,0 +1,30 @@ +package environment + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestEnvironment(t *testing.T) { + expected := map[string]any{"": 1} + env := New() + env.Set("", 1) + require.Equal(t, expected, env.Env()) +} + +func TestMockEnvironment(t *testing.T) { + env := &MockEnvironment{ + OnEnv: func() map[string]any { + return map[string]any{"": ""} + }, OnSet: func(s string, a any) { + require.Equal(t, s, a) + }, + } + require.Equal(t, "", env.Env()[""]) + env.Set("", "") +} diff --git a/samples/krill/lib/errors/errors.go b/samples/krill/lib/errors/errors.go new file mode 100644 index 0000000..0b4e5cb --- /dev/null +++ b/samples/krill/lib/errors/errors.go @@ -0,0 +1,49 @@ +package errors + +type Category int + +type Error interface { + error + Code() Category +} + +const ( + MOCK Category = iota + BAD_REQUEST + NOT_FOUND +) + +type Custom struct { + code Category + message string +} + +func (c Custom) Code() Category { + return c.code +} + +func (c Custom) Error() string { + return c.message +} + +type Mock struct{} + +func (Mock) Code() Category { + return MOCK +} + +func (Mock) Error() string { + return "mock" +} + +type BadRequest struct{} + +func (BadRequest) Code() Category { + return BAD_REQUEST +} + +type NotFound struct{} + +func (NotFound) Code() Category { + return NOT_FOUND +} diff --git a/samples/krill/lib/errors/errors_test.go b/samples/krill/lib/errors/errors_test.go new file mode 100644 index 0000000..9feec7c --- /dev/null +++ b/samples/krill/lib/errors/errors_test.go @@ -0,0 +1,143 @@ +package errors + +import ( + "net/http" + "testing" + + "github.com/gofiber/fiber/v2" + "github.com/iot-for-all/device-simulation/lib/logger" + "github.com/stretchr/testify/require" +) + +const ( + MockErrorCode = 507 + MockErrorCodeString = "507" + MockErrorMessage = "MockErrorMessage" + MockBadRequestString = "400" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestMockError(t *testing.T) { + err := &Mock{} + require.Equal(t, MOCK, err.Code()) + require.Equal(t, "mock", err.Error()) +} + +func TestBadRequest(t *testing.T) { + res := &BadRequest{} + require.Equal(t, BAD_REQUEST, res.Code()) +} + +func TestNotFound(t *testing.T) { + res := &NotFound{} + require.Equal(t, NOT_FOUND, res.Code()) +} + +func TestFiberErrorHandlerFiberError(t *testing.T) { + handler := New(func(feh *FiberErrorHandler) { + feh.Logger = &logger.MockLogger{ + OnLevel: func(i int) logger.Logger { + require.Equal(t, logger.Error, i) + return feh.Logger + }, OnWith: func(s1, s2 string) logger.Logger { + require.Equal(t, "code", s1) + require.Equal(t, MockErrorCodeString, s2) + return feh.Logger + }, OnPrintf: func(s string, i ...interface{}) { + require.Equal(t, "an internal error occurred", s) + }, + } + }) + + err := handler.HandleError(&MockContext{ + OnStatus: func(status int) Context { + require.Equal(t, MockErrorCode, status) + return &MockContext{ + OnSend: func(body []byte) error { + require.Equal(t, []byte(MockErrorMessage), body) + return nil + }, + } + }, + }, &fiber.Error{ + Code: MockErrorCode, + Message: MockErrorMessage, + }) + require.NoError(t, err) +} + +func TestFiberErrorHandlerInternalError(t *testing.T) { + handler := New(func(feh *FiberErrorHandler) { + feh.Logger = &logger.MockLogger{ + OnLevel: func(i int) logger.Logger { + require.Equal(t, logger.Debug, i) + return feh.Logger + }, OnWith: func(s1, s2 string) logger.Logger { + require.Equal(t, "code", s1) + require.Equal(t, MockBadRequestString, s2) + return feh.Logger + }, OnPrintf: func(s string, i ...interface{}) { + require.Equal(t, "an non-500-level error occurred", s) + }, + } + }) + + err := handler.HandleError(&MockContext{ + OnStatus: func(status int) Context { + require.Equal(t, http.StatusBadRequest, status) + return &MockContext{ + OnSend: func(body []byte) error { + require.Equal(t, []byte(MockErrorMessage), body) + return nil + }, + } + }, + }, &Custom{ + code: BAD_REQUEST, + message: MockErrorMessage, + }) + require.NoError(t, err) +} + +func TestFiberErrorHandlerSendError(t *testing.T) { + handler := New(func(feh *FiberErrorHandler) { + feh.Logger = &logger.MockLogger{ + OnLevel: func(i int) logger.Logger { + return feh.Logger + }, OnWith: func(s1, s2 string) logger.Logger { + return feh.Logger + }, OnPrintf: func(s string, i ...interface{}) { + feh.Logger = &logger.MockLogger{ + OnLevel: func(i int) logger.Logger { + require.Equal(t, logger.Error, i) + return feh.Logger + }, OnWith: func(s1, s2 string) logger.Logger { + require.Equal(t, "error", s1) + require.Equal(t, (Mock{}).Error(), s2) + return feh.Logger + }, OnPrintf: func(s string, i ...interface{}) { + require.Equal(t, "error occurred when handling error", s) + }, + } + }, + } + }) + + err := handler.HandleError(&MockContext{ + OnStatus: func(status int) Context { + require.Equal(t, http.StatusBadRequest, status) + return &MockContext{ + OnSend: func(body []byte) error { + return Mock{} + }, + } + }, + }, &Custom{ + code: BAD_REQUEST, + message: MockErrorMessage, + }) + require.Equal(t, Mock{}, err) +} \ No newline at end of file diff --git a/samples/krill/lib/errors/fiber.go b/samples/krill/lib/errors/fiber.go new file mode 100644 index 0000000..2562335 --- /dev/null +++ b/samples/krill/lib/errors/fiber.go @@ -0,0 +1,90 @@ +package errors + +import ( + "errors" + "fmt" + "net/http" + + "github.com/gofiber/fiber/v2" + "github.com/iot-for-all/device-simulation/lib/logger" +) + +var FiberMappings = map[Category]int{ + BAD_REQUEST: http.StatusBadRequest, + NOT_FOUND: http.StatusNotFound, +} + +type FiberErrorHandler struct { + Logger logger.Logger +} + +func New(options ...func(*FiberErrorHandler)) *FiberErrorHandler { + handler := &FiberErrorHandler{ + Logger: &logger.NoopLogger{}, + } + + for _, option := range options { + option(handler) + } + + return handler +} + +func (handler *FiberErrorHandler) HandleError(c Context, err error) error { + code := fiber.StatusInternalServerError + + var e *fiber.Error + if errors.As(err, &e) { + code = e.Code + } + + internal, ok := err.(Error) + if ok { + mapping, ok := FiberMappings[internal.Code()] + if ok { + code = mapping + } + } + + if code >= fiber.StatusInternalServerError { + handler.Logger.Level(logger.Error).With("code", fmt.Sprintf("%d", code)).Printf("an internal error occurred") + } else { + handler.Logger.Level(logger.Debug).With("code", fmt.Sprintf("%d", code)).Printf("an non-500-level error occurred") + } + + err = c.Status(code).Send([]byte(err.Error())) + if err != nil { + handler.Logger.Level(logger.Error).With("error", err.Error()).Printf("error occurred when handling error") + return err + } + + return nil +} + +type Context interface { + Status(status int) Context + Send(body []byte) error +} + +type FiberContextWrapper struct { + *fiber.Ctx +} + +func (c *FiberContextWrapper) Status(status int) Context { + return &FiberContextWrapper{ + Ctx: c.Ctx.Status(status), + } +} + +type MockContext struct { + OnStatus func(status int) Context + OnSend func(body []byte) error +} + +func (ctx *MockContext) Status(status int) Context { + return ctx.OnStatus(status) +} + +func (ctx *MockContext) Send(body []byte) error { + return ctx.OnSend(body) +} diff --git a/samples/krill/lib/exporter/exporter.go b/samples/krill/lib/exporter/exporter.go new file mode 100644 index 0000000..041e78b --- /dev/null +++ b/samples/krill/lib/exporter/exporter.go @@ -0,0 +1,153 @@ +package exporter + +import ( + "encoding/json" + "fmt" + "io" + "io/fs" + "math" + "os" + "path/filepath" + "sync" + "time" + + "github.com/iot-for-all/device-simulation/components/registry" +) + +type Exporter interface { + RegisterHistogram(name, help string, start, width int) (Provider, error) +} + +type Provider interface { + Export() error + Label(label Label) registry.CancellableObservable +} + +type ( + Label string + Kind string +) + +const ( + HISTOGRAM Kind = "histogram" + COUNTER Kind = "counter" +) + +type HistogramOptions struct { + Start int `json:"start"` + Width int `json:"width"` +} + +type HistogramProvider struct { + file io.WriteCloser + mu sync.Mutex + Marshal func(v any) ([]byte, error) + + Name string `json:"name"` + Help string `json:"help"` + Kind Kind `json:"kind"` + Options HistogramOptions `json:"options"` + Data map[Label]map[int]int `json:"data"` +} + +func (provider *HistogramProvider) Export() error { + provider.mu.Lock() + defer provider.mu.Unlock() + + content, err := provider.Marshal(provider) + if err != nil { + return err + } + + _, err = provider.file.Write(content) + if err != nil { + return err + } + + return provider.file.Close() +} + +func (provider *HistogramProvider) Label(label Label) registry.CancellableObservable { + provider.mu.Lock() + defer provider.mu.Unlock() + histogram := &Histogram{ + Data: make(map[int]int), + options: provider.Options, + } + provider.Data[label] = histogram.Data + + return histogram +} + +type Histogram struct { + mu sync.Mutex + options HistogramOptions + Data map[int]int `json:"data"` +} + +func (histogram *Histogram) Observe(value float64) { + histogram.mu.Lock() + defer histogram.mu.Unlock() + + histogram.Data[(int(math.Floor(value))-histogram.options.Start)/histogram.options.Width]++ +} + +func (histogram *Histogram) Cancel() {} + +type Opener interface { + Open(filename string) (io.WriteCloser, error) +} + +type FileExporter struct { + opener Opener +} + +func NewExporter(opener Opener) *FileExporter { + return &FileExporter{ + opener: opener, + } +} + +func (exporter *FileExporter) RegisterHistogram(name, help string, start, width int) (Provider, error) { + + now := time.Now() + f, err := exporter.opener.Open(fmt.Sprintf("D%s-T%d-%d-%d-histogram-%s.json", now.Format(time.DateOnly), now.Hour(), now.Minute(), now.Second(), name)) + if err != nil { + return nil, err + } + + return &HistogramProvider{ + file: f, + Name: name, + Kind: HISTOGRAM, + Help: help, + Marshal: json.Marshal, + Options: HistogramOptions{ + Start: start, + Width: width, + }, + Data: make(map[Label]map[int]int), + }, nil +} + +type FileOpener struct { + storage string + OpenFile func(name string, flag int, perm fs.FileMode) (*os.File, error) +} + +func NewOpener(storage string, options ...func(*FileOpener)) *FileOpener { + opener := &FileOpener{ + storage: storage, + OpenFile: os.OpenFile, + } + + for _, option := range options { + option(opener) + } + + return opener +} + +func (fileOpener *FileOpener) Open(filename string) (io.WriteCloser, error) { + return fileOpener.OpenFile(filepath.Join(fileOpener.storage, filename), os.O_RDWR|os.O_CREATE, 0755) +} diff --git a/samples/krill/lib/exporter/exporter_test.go b/samples/krill/lib/exporter/exporter_test.go new file mode 100644 index 0000000..ca0e085 --- /dev/null +++ b/samples/krill/lib/exporter/exporter_test.go @@ -0,0 +1,236 @@ +package exporter + +import ( + "io" + "io/fs" + "os" + "testing" + + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/lib/logger" + "github.com/stretchr/testify/require" +) + +const ( + MockLabel = "MockLabel" +) + +var ( + MockContent = []byte{0, 1} +) + +type MockError struct{} + +func (*MockError) Error() string { + return "mock" +} + +func TestMain(m *testing.M) { + m.Run() +} + +func TestHistogram(t *testing.T) { + exporter := NewExporter(&MockOpener{ + OnOpen: func(string) (io.WriteCloser, error) { + return nil, nil + }, + }) + + provider, err := exporter.RegisterHistogram("", "", 0, 10) + require.NoError(t, err) + + histProvider, ok := provider.(*HistogramProvider) + require.True(t, ok) + + histogram := provider.Label("") + + histogram.Observe(20) + + require.Equal(t, 1, histProvider.Data[""][2]) + + histogram.Observe(19) + + require.Equal(t, 1, histProvider.Data[""][1]) +} + +func TestHistogramNonZeroStart(t *testing.T) { + exporter := NewExporter(&MockOpener{ + OnOpen: func(string) (io.WriteCloser, error) { + return nil, nil + }, + }) + + provider, err := exporter.RegisterHistogram("", "", 10, 10) + require.NoError(t, err) + + histProvider, ok := provider.(*HistogramProvider) + require.True(t, ok) + + histogram := provider.Label("") + + histogram.Observe(20) + + require.Equal(t, 1, histProvider.Data[""][1]) + + histogram.Observe(19) + + require.Equal(t, 1, histProvider.Data[""][0]) +} + +func TestOpenerError(t *testing.T) { + exporter := NewExporter(&MockOpener{ + OnOpen: func(string) (io.WriteCloser, error) { + return nil, &MockError{} + }, + }) + _, err := exporter.RegisterHistogram("", "", 0, 0) + require.Equal(t, &MockError{}, err) +} + +func TestFileOpener(t *testing.T) { + opener := NewOpener("", func(fo *FileOpener) { + fo.OpenFile = func(name string, flag int, perm fs.FileMode) (*os.File, error) { + return nil, nil + } + }) + + _, err := opener.Open("") + require.NoError(t, err) +} + +func TestMockExporter(t *testing.T) { + exporter := &MockExporter{ + OnRegisterHistogram: func(name, help string, start, width int) (Provider, error) { + return nil, nil + }, + } + + _, err := exporter.RegisterHistogram("", "", 0, 0) + require.NoError(t, err) +} + +func TestHistogramProvider(t *testing.T) { + provider := &HistogramProvider{ + file: &MockFile{ + OnWrite: func(p []byte) (n int, err error) { + require.Equal(t, MockContent, p) + return 0, nil + }, OnClose: func() error { + return nil + }, + }, Marshal: func(v any) ([]byte, error) { + return MockContent, nil + }, + } + + require.NoError(t, provider.Export()) +} + +func TestHistogramProviderMarshalError(t *testing.T) { + provider := &HistogramProvider{ + file: &MockFile{ + OnWrite: func(p []byte) (n int, err error) { + return 0, nil + }, OnClose: func() error { + return nil + }, + }, Marshal: func(v any) ([]byte, error) { + return nil, &MockError{} + }, + } + + require.Equal(t, &MockError{}, provider.Export()) +} + +func TestHistogramProviderFileWriteError(t *testing.T) { + provider := &HistogramProvider{ + file: &MockFile{ + OnWrite: func(p []byte) (n int, err error) { + return 0, &MockError{} + }, OnClose: func() error { + return nil + }, + }, Marshal: func(v any) ([]byte, error) { + return nil, nil + }, + } + + require.Equal(t, &MockError{}, provider.Export()) +} + +func TestCustomHistogramProvider(t *testing.T) { + provider, err := New(&MockExporter{ + OnRegisterHistogram: func(name, help string, start, width int) (Provider, error) { + return &MockProvider{ + OnExport: func() error { + return nil + }, OnLabel: func(label Label) registry.CancellableObservable { + require.Equal(t, MockLabel, string(label)) + return nil + }, + }, nil + }, + }, func(chp *CustomHistogramProvider) { + chp.Logger = &logger.NoopLogger{} + }) + require.NoError(t, err) + + _, err = provider.With(MockLabel) + require.NoError(t, err) +} + +func TestCustomHistogramProviderCancelError(t *testing.T) { + provider, err := New(&MockExporter{ + OnRegisterHistogram: func(name, help string, start, width int) (Provider, error) { + return &MockProvider{ + OnExport: func() error { + return &MockError{} + }, OnLabel: func(label Label) registry.CancellableObservable { + return nil + }, + }, nil + }, + }, func(chp *CustomHistogramProvider) { + chp.Logger = &logger.MockLogger{ + OnLevel: func(i int) logger.Logger { + require.Equal(t, logger.Error, i) + return chp.Logger + }, OnWith: func(s1, s2 string) logger.Logger { + require.Equal(t, "error", s1) + require.Equal(t, (&MockError{}).Error(), s2) + return chp.Logger + }, OnPrintf: func(s string, i ...interface{}) { + require.Equal(t, "could not export data to file", s) + }, + } + }) + require.NoError(t, err) + + require.Equal(t, &MockError{}, provider.Cancel()) +} + +func TestCustomHistogramProviderRegistrationError(t *testing.T) { + _, err := New(&MockExporter{ + OnRegisterHistogram: func(name, help string, start, width int) (Provider, error) { + return nil, &MockError{} + }, + }) + require.Equal(t, &MockError{}, err) +} + +func TestStat(t *testing.T) { + err := Stat(".") + require.NoError(t, err) +} + +func TestStatInvalidVolumeError(t *testing.T) { + err := Stat("") + require.Equal(t, (&InvalidVolumePath{}).Error(), err.Error()) +} + +func TestStatError(t *testing.T) { + err := Stat("\u0000") + require.Error(t, err) + _, ok := err.(*InvalidVolumePath) + require.False(t, ok) +} diff --git a/samples/krill/lib/exporter/mock.go b/samples/krill/lib/exporter/mock.go new file mode 100644 index 0000000..c919f65 --- /dev/null +++ b/samples/krill/lib/exporter/mock.go @@ -0,0 +1,49 @@ +package exporter + +import ( + "io" + + "github.com/iot-for-all/device-simulation/components/registry" +) + +type MockExporter struct { + OnRegisterHistogram func(name, help string, start, width int) (Provider, error) +} + +func (exporter *MockExporter) RegisterHistogram(name, help string, start, width int) (Provider, error) { + return exporter.OnRegisterHistogram(name, help, start, width) +} + +type MockOpener struct { + OnOpen func(filename string) (io.WriteCloser, error) +} + +func (opener *MockOpener) Open(filename string) (io.WriteCloser, error) { + return opener.OnOpen(filename) +} + +type MockFile struct { + OnWrite func(p []byte) (n int, err error) + OnClose func() error +} + +func (file *MockFile) Write(p []byte) (n int, err error) { + return file.OnWrite(p) +} + +func (file *MockFile) Close() error { + return file.OnClose() +} + +type MockProvider struct { + OnExport func() error + OnLabel func(label Label) registry.CancellableObservable +} + +func (provider *MockProvider) Export() error { + return provider.OnExport() +} + +func (provider *MockProvider) Label(label Label) registry.CancellableObservable { + return provider.OnLabel(label) +} diff --git a/samples/krill/lib/exporter/provider.go b/samples/krill/lib/exporter/provider.go new file mode 100644 index 0000000..047aa86 --- /dev/null +++ b/samples/krill/lib/exporter/provider.go @@ -0,0 +1,50 @@ +package exporter + +import ( + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/lib/logger" +) + +type CustomHistogramProvider struct { + provider Provider + Name string + Help string + Start int + Width int + Logger logger.Logger +} + +func New(exporter Exporter, options ...func(*CustomHistogramProvider)) (*CustomHistogramProvider, error) { + provider := &CustomHistogramProvider{ + Logger: &logger.NoopLogger{}, + } + + for _, option := range options { + option(provider) + } + + histProv, err := exporter.RegisterHistogram(provider.Name, provider.Help, provider.Start, provider.Width) + if err != nil { + return nil, err + } + + provider.provider = histProv + + return provider, nil +} + +func (provider *CustomHistogramProvider) Cancel() error { + err := provider.provider.Export() + if err != nil { + provider.Logger.Level(logger.Error).With("error", err.Error()).Printf("could not export data to file") + return err + } + + return nil +} + +func (provider *CustomHistogramProvider) With( + label string, +) (registry.CancellableObservable, error) { + return provider.provider.Label(Label(label)), nil +} \ No newline at end of file diff --git a/samples/krill/lib/exporter/stat.go b/samples/krill/lib/exporter/stat.go new file mode 100644 index 0000000..3508f10 --- /dev/null +++ b/samples/krill/lib/exporter/stat.go @@ -0,0 +1,29 @@ +package exporter + +import ( + "fmt" + "os" +) + + +type InvalidVolumePath struct { + path string +} + +func (err *InvalidVolumePath) Error() string { + return fmt.Sprintf("no storage directory exists at path %s, please check for misconfigurations", err.path) +} + +func Stat(path string) error { + _, err := os.Stat(path) + if os.IsNotExist(err) { + return &InvalidVolumePath{ + path: path, + } + } + if err != nil { + return err + } + + return nil +} \ No newline at end of file diff --git a/samples/krill/lib/expression/expression.go b/samples/krill/lib/expression/expression.go new file mode 100644 index 0000000..0f318cb --- /dev/null +++ b/samples/krill/lib/expression/expression.go @@ -0,0 +1,465 @@ +// Package expression provides functionality to evaluate simple mathematic expressions and functions. +package expression + +import ( + "errors" + "fmt" + "go/ast" + "go/token" + "math" + "math/rand" + "strconv" + "strings" + "time" +) + +// Evaluator is an interface whose implementation should be able to evaluate basic expressions given an evaluation context. +// From this context, a float64 should be evaluated, or an error if an evaluation error occurs. +type Evaluator interface { + Evaluate(map[string]any) (any, error) +} + +// Errors which may occur during expression evaluation. +var ( + ErrCannotEvaluateExpr = errors.New( + "could not evaluate expression", + ) + ErrCannotEvaluateLiteral = errors.New("could not evaluate literal") + ErrCallExpressionInvalid = errors.New( + "could not evaluate call expression name", + ) + ErrFunctionDoesNotExist = errors.New("function does not exist") + ErrCannotEvaluateBinaryOpToken = errors.New( + "could not evaluate binary op token", + ) + ErrCannotEvaluateUnaryOpToken = errors.New( + "could not evaluate unary op token", + ) + ErrIncorrectArgumentCount = errors.New( + "too many or too few arguments were supplied to the function", + ) + ErrInvalidFunctionArguments = errors.New( + "the supplied function arguments are the correct type but are invalid", + ) + ErrIdentNotFound = errors.New( + "the ident could not be found in the evaluation context", + ) + ErrUnaryExpressionMustBeNumeric = errors.New( + "unary expressions such as '-' can only be applied on numbers", + ) + ErrBinaryExpressionMustBeNumeric = errors.New( + "binary expressions such as '+' or '*' can only be applied on numbers of the same type (both ints or both floats)", + ) + ErrInvalidFunctionArgumentType = errors.New( + "the supplied function arguments are invalid", + ) + ErrInvalidSelector = errors.New( + "selector cannot be used on a non-map type", + ) +) + +// FunctionType is an enum representing the functions which can be evaluated by the evaluator. +type FunctionType string + +// Names of each function which can be evaluated by the evaluator. +const ( + SIN FunctionType = "sin" + COS FunctionType = "cos" + TAN FunctionType = "tan" + ASIN FunctionType = "asin" + ACOS FunctionType = "acos" + ATAN FunctionType = "atan" + RAND FunctionType = "rand" + STR FunctionType = "str" + CONCAT FunctionType = "concat" + RANDSTR FunctionType = "randstr" + NOW FunctionType = "now" + DELTA FunctionType = "delta" + TOINT FunctionType = "int" + TOFLOAT FunctionType = "float" + AFTER FunctionType = "after" + ABS FunctionType = "abs" + PI FunctionType = "pi" +) + +type OperandType int + +const ( + FLOAT OperandType = iota + STRING + DATETIME + INTEGER + VOID +) + +var FunctionTypeOperandTypeMapping = map[FunctionType][]OperandType{ + SIN: {FLOAT}, + COS: {FLOAT}, + TAN: {FLOAT}, + ASIN: {FLOAT}, + ACOS: {FLOAT}, + ATAN: {FLOAT}, + RAND: {INTEGER, INTEGER}, + STR: {FLOAT, INTEGER}, + CONCAT: {STRING, STRING}, + RANDSTR: {INTEGER}, + NOW: {VOID}, + DELTA: {DATETIME, DATETIME}, + AFTER: {DATETIME, INTEGER}, + TOINT: {FLOAT}, + TOFLOAT: {INTEGER}, + ABS: {FLOAT}, + PI: {VOID}, +} + +var OperandTypeValidationMapping = map[OperandType]func(any) bool{ + FLOAT: func(a any) bool { + _, b := a.(float64) + return b + }, + STRING: func(a any) bool { + _, b := a.(string) + return b + }, + DATETIME: func(a any) bool { + _, b := a.(time.Time) + return b + }, + INTEGER: func(a any) bool { + _, b := a.(int) + return b + }, +} + +const ( + letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +) + +var FunctionTypeFunctionCurryMappings = map[FunctionType]any{ + RAND: func(i0 int) any { + return func(i1 int) any { + return rand.Intn(i1-i0) + i0 // #nosec G404 + } + }, + SIN: func(f0 float64) any { return math.Sin(f0) }, + COS: func(f0 float64) any { return math.Cos(f0) }, + TAN: func(f0 float64) any { return math.Tan(f0) }, + ASIN: func(f0 float64) any { return math.Asin(f0) }, + ACOS: func(f0 float64) any { return math.Acos(f0) }, + ATAN: func(f0 float64) any { return math.Atan(f0) }, + STR: func(f0 float64) any { + return func(i0 int) any { + return fmt.Sprintf(fmt.Sprintf("%%0.%df", i0), f0) + } + }, + RANDSTR: func(i0 int) any { + + str := make([]byte, i0) + + randoms := rand.Perm(len(letterBytes) - 1) + + for idx := 0; idx < i0; idx++ { + str[idx] = letterBytes[randoms[idx]] + } + + return string(str) + + }, + TOINT: func(f0 float64) any { return int(f0) }, + CONCAT: func(s0 string) any { + return func(s1 string) any { + return fmt.Sprintf("%s%s", s0, s1) + } + }, + NOW: func() any { return time.Now() }, + DELTA: func(t0 time.Time) any { + return func(t1 time.Time) any { + if t0.After(t1) { + return int(t0.Sub(t1).Milliseconds()) + } else { + return int(t1.Sub(t0).Milliseconds()) + } + } + }, + TOFLOAT: func(i0 int) any { return float64(i0) }, + AFTER: func(t0 time.Time) any { + return func(i0 int) any { + return t0.Add(time.Duration(i0) * time.Millisecond) + } + }, + ABS: func(f0 float64) any { return math.Abs(f0) }, + PI: func() any { return math.Pi }, +} + +// FunctionValidationMapping describes a validation function which will be run before the functions in the mapping above are called. +// This assures that no panics will occur in the evaluation of the above functions, +// and also that NaN will not be returned. +var FunctionValidationMapping = map[FunctionType]func(...float64) bool{ + SIN: func(f ...float64) bool { return math.IsNaN(f[0]) || math.IsInf(f[0], 0) }, + COS: func(f ...float64) bool { return math.IsNaN(f[0]) || math.IsInf(f[0], 0) }, + TAN: func(f ...float64) bool { return math.IsNaN(f[0]) || math.IsInf(f[0], 0) }, + ASIN: func(f ...float64) bool { return f[0] < -1 || f[0] > 1 }, + ACOS: func(f ...float64) bool { return f[0] < -1 || f[0] > 1 }, + ATAN: func(f ...float64) bool { return true }, + RAND: func(f ...float64) bool { return f[0] > f[1] }, + STR: func(f ...float64) bool { + return math.IsNaN(f[0]) || math.IsInf(f[0], 0) || math.IsNaN(f[0]) || + math.IsInf(f[0], 0) || + f[1] > 10 + }, + RANDSTR: func(f ...float64) bool { + return math.IsNaN(f[0]) || math.IsInf(f[0], 0) || f[0] < 1 + }, +} + +// Expression is an implementation of evaluator. +// It holds the underlying golang AST expression and provides an evaluation function which can be applied on the given expression. +type Expression struct { + expr ast.Expr +} + +// New creates an Expression, given an ast expression. +func New(expr ast.Expr) *Expression { + return &Expression{ + expr: expr, + } +} + +// Evaluate will resolve the expression's ast expression to a float64 value, +// given an environment of key value pairs which can be used to resolve symbols in the expression. +// An error will be returned if the expression cannot evaluate for any reason. +func (expression *Expression) Evaluate(env map[string]any) (any, error) { + return evalExpr(env, expression.expr) +} + +func evalExpr(env map[string]any, n ast.Expr) (any, error) { + switch expr := n.(type) { + case *ast.BinaryExpr: + return evalBinaryExpr(env, expr) + case *ast.CallExpr: + return evalCallExpr(env, expr) + case *ast.UnaryExpr: + return evalUnaryExpr(env, expr) + case *ast.SelectorExpr: + return evalSelectorExpr(env, expr) + case *ast.Ident: + return evalIdent(env, expr) + case *ast.ParenExpr: + return evalExpr(env, expr.X) + case *ast.BasicLit: + return evalBasicLit(expr) + default: + return 0, ErrCannotEvaluateExpr + } +} + +func evalSelectorExpr(env map[string]any, expr *ast.SelectorExpr) (any, error) { + res, err := evalExpr(env, expr.X) + if err != nil { + return 0, err + } + + m, ok := res.(map[string]any) + if !ok { + return 0, ErrInvalidSelector + } + + return evalIdent(m, expr.Sel) +} + +func evalBasicLit(lit *ast.BasicLit) (any, error) { + switch lit.Kind { + case token.INT: + return strconv.Atoi(lit.Value) + case token.FLOAT: + return strconv.ParseFloat(lit.Value, 64) + case token.STRING: + return strings.Trim(lit.Value, "\""), nil + default: + return 0, ErrCannotEvaluateLiteral + } +} + +func evalIdent(env map[string]any, ident *ast.Ident) (any, error) { + res, ok := env[ident.Name] + if !ok { + return 0, ErrIdentNotFound + } + + return res, nil +} + +func evalUnaryExpr(env map[string]any, expr *ast.UnaryExpr) (any, error) { + res, err := evalExpr(env, expr.X) + if err != nil { + return 0, err + } + + switch expr.Op { + case token.SUB: + switch val := res.(type) { + case float64: + return -1 * val, nil + case int: + return -1 * val, nil + default: + return 0, ErrUnaryExpressionMustBeNumeric + } + default: + return 0, ErrCannotEvaluateUnaryOpToken + } +} + +func evalCallExpr(env map[string]any, expr *ast.CallExpr) (any, error) { + ident, ok := expr.Fun.(*ast.Ident) + if !ok { + return 0, ErrCallExpressionInvalid + } + + typeMappings, ok := FunctionTypeOperandTypeMapping[FunctionType(ident.Name)] + if !ok { + return 0, ErrFunctionDoesNotExist + } + + // If the function is a void function, evaluate immediately and return result. + if typeMappings[0] == VOID { + return FunctionTypeFunctionCurryMappings[FunctionType(ident.Name)].(func() any)(), nil + } + + if len(typeMappings) != len(expr.Args) { + return 0, ErrIncorrectArgumentCount + } + + args := make([]any, len(typeMappings)) + + for idx, arg := range expr.Args { + res, err := evalExpr(env, arg) + if err != nil { + return 0, err + } + args[idx] = res + } + + f := FunctionTypeFunctionCurryMappings[FunctionType(ident.Name)] + + for idx, opType := range typeMappings { + if OperandTypeValidationMapping[opType](args[idx]) { + switch opType { + case FLOAT: + f = f.(func(float64) any)(args[idx].(float64)) + case STRING: + f = f.(func(string) any)(args[idx].(string)) + case DATETIME: + f = f.(func(time.Time) any)(args[idx].(time.Time)) + case INTEGER: + f = f.(func(int) any)(args[idx].(int)) + } + } else { + return 0, ErrInvalidFunctionArgumentType + } + } + + return f, nil +} + +var BinaryExprFunctionMapping = map[OperandType]map[token.Token]any{ + FLOAT: { + token.ADD: func(f0, f1 float64) any { + return f0 + f1 + }, + token.SUB: func(f0, f1 float64) any { + return f0 - f1 + }, + token.MUL: func(f0, f1 float64) any { + return f0 * f1 + }, + token.QUO: func(f0, f1 float64) any { + if f1 == 0 { + return 0 + } + return f0 / f1 + }, + token.XOR: func(f0, f1 float64) any { + return math.Pow(f0, f1) + }, + }, INTEGER: { + token.ADD: func(i0, i1 int) any { + return i0 + i1 + }, + token.SUB: func(i0, i1 int) any { + return i0 - i1 + }, + token.MUL: func(i0, i1 int) any { + return i0 * i1 + }, + token.QUO: func(i0, i1 int) any { + if i1 == 0 { + return 0 + } + return i0 / i1 + }, + token.XOR: func(i0, i1 int) any { + res := i0 + for count := 1; count < i1; count++ { + res *= i0 + } + return res + }, + token.REM: func(i0, i1 int) any { + if i1 == 0 { + return 0 + } + return i0 % i1 + }, + }, +} + +func evalBinaryExpr(env map[string]any, expr *ast.BinaryExpr) (any, error) { + lhs, err := evalExpr(env, expr.X) + if err != nil { + return 0, err + } + + rhs, err := evalExpr(env, expr.Y) + if err != nil { + return 0, err + } + + switch lVal := lhs.(type) { + case float64: + rVal, ok := rhs.(float64) + if !ok { + return 0, ErrBinaryExpressionMustBeNumeric + } + + mappings, ok := BinaryExprFunctionMapping[FLOAT][expr.Op] + if !ok { + return 0, ErrCannotEvaluateBinaryOpToken + } + + return mappings.(func(float64, float64) any)(lVal, rVal), nil + + case int: + rVal, ok := rhs.(int) + if !ok { + return 0, ErrBinaryExpressionMustBeNumeric + } + + mappings, ok := BinaryExprFunctionMapping[INTEGER][expr.Op] + if !ok { + return 0, ErrCannotEvaluateBinaryOpToken + } + + return mappings.(func(int, int) any)(lVal, rVal), nil + default: + return 0, ErrBinaryExpressionMustBeNumeric + } +} + +type MockEvaluator struct { + OnEvaluate func(map[string]any) (any, error) +} + +func (evaluator *MockEvaluator) Evaluate(m map[string]any) (any, error) { + return evaluator.OnEvaluate(m) +} \ No newline at end of file diff --git a/samples/krill/lib/expression/expression_test.go b/samples/krill/lib/expression/expression_test.go new file mode 100644 index 0000000..f84d1d4 --- /dev/null +++ b/samples/krill/lib/expression/expression_test.go @@ -0,0 +1,200 @@ +package expression + +import ( + "go/parser" + "math" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestSimpleExpression(t *testing.T) { + psr, err := parser.ParseExpr("1") + require.NoError(t, err) + + expr := New(psr) + res, err := expr.Evaluate(nil) + require.NoError(t, err) + + require.Equal(t, 1, res) +} + +func TestSimpleBinaryExpression(t *testing.T) { + psr, err := parser.ParseExpr("1 + 1") + require.NoError(t, err) + + expr := New(psr) + res, err := expr.Evaluate(nil) + require.NoError(t, err) + + require.Equal(t, 2, res) +} + +func TestSimpleStringExpression(t *testing.T) { + psr, err := parser.ParseExpr(`"expected"`) + require.NoError(t, err) + + expr := New(psr) + res, err := expr.Evaluate(nil) + require.NoError(t, err) + + require.Equal(t, "expected", res) +} + +func TestSimpleStringFunctionCallExpression(t *testing.T) { + psr, err := parser.ParseExpr(`concat("hello", concat(" ", "world"))`) + require.NoError(t, err) + + expr := New(psr) + res, err := expr.Evaluate(nil) + require.NoError(t, err) + + require.Equal(t, "hello world", res) +} + +func TestStringConversionFunctionCallExpression(t *testing.T) { + psr, err := parser.ParseExpr(`concat("hello", concat(" ", str(100.0, 3)))`) + require.NoError(t, err) + + expr := New(psr) + res, err := expr.Evaluate(nil) + require.NoError(t, err) + + require.Equal(t, "hello 100.000", res) +} + +func TestSelectorExpression(t *testing.T) { + psr, err := parser.ParseExpr(`x.y.z`) + require.NoError(t, err) + + expr := New(psr) + res, err := expr.Evaluate(map[string]any{ + "x": map[string]any{ + "y": map[string]any{ + "z": 10, + }, + }, + }) + require.NoError(t, err) + + require.Equal(t, 10, res) +} + +func TestCallExpressionWithIdent(t *testing.T) { + psr, err := parser.ParseExpr(`sin(pi)`) + require.NoError(t, err) + + expr := New(psr) + res, err := expr.Evaluate(map[string]any{ + "pi": math.Pi, + }) + require.NoError(t, err) + require.InDelta(t, 0.0, res, 0.00000001) +} + +func TestCallExpressionWithNestedIdent(t *testing.T) { + psr, err := parser.ParseExpr(`cos(x.y.z)`) + require.NoError(t, err) + + expr := New(psr) + res, err := expr.Evaluate(map[string]any{ + "x": map[string]any{ + "y": map[string]any{ + "z": 0.0, + }, + }, + }) + require.NoError(t, err) + require.Equal(t, 1.0, res) +} + +func TestAllExpressions(t *testing.T) { + psr, err := parser.ParseExpr( + `(concat("100 =" ,concat(" ", str(-(-(cos(x.y.z - sin(2.0 * pi) - 1.0) + 99.0)), 0))))`, + ) + require.NoError(t, err) + + expr := New(psr) + res, err := expr.Evaluate(map[string]any{ + "x": map[string]any{ + "y": map[string]any{ + "z": 1.0, + }, + }, + "pi": math.Pi, + }) + require.NoError(t, err) + require.Equal(t, "100 = 100", res) +} + +func TestRandomString(t *testing.T) { + psr, err := parser.ParseExpr(`randstr(10)`) + require.NoError(t, err) + + expr := New(psr) + res, err := expr.Evaluate(nil) + require.NoError(t, err) + + val, ok := res.(string) + require.Equal(t, true, ok) + + require.Equal(t, 10, len(val)) +} + +func TestBasicTimeCallExpression(t *testing.T) { + psr, err := parser.ParseExpr(`now()`) + require.NoError(t, err) + + expr := New(psr) + res, err := expr.Evaluate(nil) + require.NoError(t, err) + + _, ok := res.(time.Time) + require.Equal(t, true, ok) +} + +func TestTimeCallExpression(t *testing.T) { + psr, err := parser.ParseExpr(`delta(now(), t)`) + require.NoError(t, err) + + expr := New(psr) + res, err := expr.Evaluate(map[string]any{ + "t": time.Now(), + }) + require.NoError(t, err) + + val, ok := res.(int) + require.Equal(t, true, ok) + require.LessOrEqual(t, 0, val) +} + +func TestIntPowerExpression(t *testing.T) { + psr, err := parser.ParseExpr(`2 ^ 3`) + require.NoError(t, err) + + expr := New(psr) + res, err := expr.Evaluate(map[string]any{}) + require.NoError(t, err) + + val, ok := res.(int) + require.Equal(t, true, ok) + require.Equal(t, 8, val) +} + +func TestFloatPowerExpression(t *testing.T) { + psr, err := parser.ParseExpr(`2.0 ^ 3.0`) + require.NoError(t, err) + + expr := New(psr) + res, err := expr.Evaluate(map[string]any{}) + require.NoError(t, err) + + val, ok := res.(float64) + require.Equal(t, true, ok) + require.Equal(t, 8.0, val) +} \ No newline at end of file diff --git a/samples/krill/lib/flatten/flatten.go b/samples/krill/lib/flatten/flatten.go new file mode 100644 index 0000000..9cad9bb --- /dev/null +++ b/samples/krill/lib/flatten/flatten.go @@ -0,0 +1,103 @@ +package flatten + +import ( + "errors" + "fmt" + "time" +) + +var ( + ErrInvalidType = errors.New("this type cannot be flattened") +) + +type Flattener interface { + Flatten(parent string, entry any) ([]Field, error) +} + +type CSVFlattener struct { + MergeStrings func(string, string) string + MergeStringAndInt func(string, int) string + FormatDatetime func(time.Time) string + FormatFloat func(float64) string +} + +func New(options ...func(*CSVFlattener)) *CSVFlattener { + flattener := &CSVFlattener{ + MergeStrings: func(s1, s2 string) string { + return fmt.Sprintf("%s__%s", s1, s2) + }, MergeStringAndInt: func(s string, i int) string { + return fmt.Sprintf("%s__field_%d", s, i) + }, FormatDatetime: func(t time.Time) string { + return t.Format(time.UnixDate) + }, FormatFloat: func(f float64) string { + return fmt.Sprintf("%0.2f", f) + }, + } + + for _, option := range options { + option(flattener) + } + + return flattener +} + +type Field struct { + Key string + Value string +} + +func (flattener *CSVFlattener) Flatten(parent string, entry any) ([]Field, error) { + + var fields []Field + + switch e := entry.(type) { + case map[string]any: + for k, v := range e { + res, err := flattener.Flatten(flattener.MergeStrings(parent, k), v) + if err != nil { + return nil, err + } + fields = append(fields, res...) + } + case []any: + for idx, v := range e { + res, err := flattener.Flatten(flattener.MergeStringAndInt(parent, idx), v) + if err != nil { + return nil, err + } + fields = append(fields, res...) + } + case int: + return []Field{{ + Key: parent, + Value: fmt.Sprintf("%d", e), + }}, nil + case float64: + return []Field{{ + Key: parent, + Value: flattener.FormatFloat(e), + }}, nil + case string: + return []Field{{ + Key: parent, + Value: e, + }}, nil + case time.Time: + return []Field{{ + Key: parent, + Value: flattener.FormatDatetime(e), + }}, nil + default: + return nil, ErrInvalidType + } + + return fields, nil +} + +type MockFlattener struct { + OnFlatten func(parent string, entry any) ([]Field, error) +} + +func (flattener *MockFlattener) Flatten(parent string, entry any) ([]Field, error) { + return flattener.OnFlatten(parent, entry) +} diff --git a/samples/krill/lib/flatten/flatten_test.go b/samples/krill/lib/flatten/flatten_test.go new file mode 100644 index 0000000..890ffa9 --- /dev/null +++ b/samples/krill/lib/flatten/flatten_test.go @@ -0,0 +1,88 @@ +package flatten + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestBasicType(t *testing.T) { + flattener := New() + + fields, err := flattener.Flatten("key", 1) + require.NoError(t, err) + + require.Equal(t, 1, len(fields)) + require.Equal(t, Field{ + Key: "key", + Value: "1", + }, fields[0]) +} + +func TestBasicTypeArray(t *testing.T) { + flattener := New() + + fields, err := flattener.Flatten("key", []any{1, "2"}) + require.NoError(t, err) + + require.Equal(t, 2, len(fields)) + require.Equal(t, []Field{{ + Key: "key__field_0", + Value: "1", + }, { + Key: "key__field_1", + Value: "2", + }}, fields) +} + +func TestBasicTypeMap(t *testing.T) { + flattener := New() + + fields, err := flattener.Flatten("key", map[string]any{"field_0": "1", "field_1": 2.0}) + require.NoError(t, err) + + require.Equal(t, 2, len(fields)) + require.ElementsMatch(t, []Field{{ + Key: "key__field_0", + Value: "1", + }, { + Key: "key__field_1", + Value: "2.00", + }}, fields) +} + +func TestComplexTypeMap(t *testing.T) { + flattener := New() + + fields, err := flattener.Flatten("key", map[string]any{"field_0": "1", "field_1": []any{2, "3"}}) + require.NoError(t, err) + + require.Equal(t, 3, len(fields)) + require.ElementsMatch(t, []Field{{Key: "key__field_0", Value: "1"}, {Key: "key__field_1__field_0", Value: "2"}, {Key: "key__field_1__field_1", Value: "3"}}, fields) +} + +func TestDatetime(t *testing.T) { + flattener := New() + + ts := time.Now() + + fields, err := flattener.Flatten("key", ts) + require.NoError(t, err) + + require.Equal(t, 1, len(fields)) + require.Equal(t, []Field{{Key: "key", Value: flattener.FormatDatetime(ts)}}, fields) +} + +func TestInvalidType(t *testing.T) { + flattener := New() + + type invalid int + + _, err := flattener.Flatten("key", invalid(1)) + require.Equal(t, ErrInvalidType, err) +} diff --git a/samples/krill/lib/gauge/gauge.go b/samples/krill/lib/gauge/gauge.go new file mode 100644 index 0000000..90dd0e4 --- /dev/null +++ b/samples/krill/lib/gauge/gauge.go @@ -0,0 +1,129 @@ +package gauge + +import ( + "fmt" + + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/lib/errors" + "github.com/prometheus/client_golang/prometheus" +) + +type Provider struct { + Vec *prometheus.GaugeVec + registry prometheus.Registerer + Name string + Help string + Label string +} + +const ( + GaugeLabelKey = "gauge" + SimulationGaugeDefaultName = "simulation_gauge" + SimulationGaugeDefaultHelp = "Simulation gauge" +) + +type InvalidPrometheusGaugeVecNameError struct { + errors.BadRequest + name string +} + +func (err *InvalidPrometheusGaugeVecNameError) Error() string { + return fmt.Sprintf( + "could not create the gauge provider with the name %s because the name has already been registered or is invalid", + err.name, + ) +} + +type InvalidPrometheusGaugeLabelError struct { + errors.BadRequest + name string + label string +} + +func (err *InvalidPrometheusGaugeLabelError) Error() string { + return fmt.Sprintf( + "could not create the prometheus gauge with label %s from gauge provider %s because the label has already been used or is invalid", + err.label, + err.name, + ) +} + +func New( + reg prometheus.Registerer, + options ...func(*Provider), +) (*Provider, error) { + provider := &Provider{ + registry: reg, + Label: GaugeLabelKey, + Name: SimulationGaugeDefaultName, + Help: SimulationGaugeDefaultHelp, + } + + for _, option := range options { + option(provider) + } + + provider.Vec = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: provider.Name, + Help: provider.Help, + }, + []string{provider.Label}, + ) + + err := provider.registry.Register(provider.Vec) + + if err != nil { + return nil, &InvalidPrometheusGaugeVecNameError{ + name: provider.Name, + } + } + + return provider, nil +} + +func (provider *Provider) Cancel() error { + provider.registry.Unregister(provider.Vec) + return nil +} + +func (provider *Provider) With( + label string, +) (registry.CancellableObservable, error) { + + counter, err := provider.Vec.GetMetricWith( + prometheus.Labels{provider.Label: label}, + ) + + if err != nil { + return nil, &InvalidPrometheusGaugeLabelError{ + name: provider.Name, + label: label, + } + } + + return NewGauge(provider.registry, counter), nil +} + +type Gauge struct { + observable prometheus.Gauge + registry prometheus.Registerer +} + +func NewGauge( + reg prometheus.Registerer, + observable prometheus.Gauge, +) *Gauge { + return &Gauge{ + registry: reg, + observable: observable, + } +} + +func (gauge Gauge) Cancel() { + gauge.registry.Unregister(gauge.observable) +} + +func (gauge Gauge) Observe(f float64) { + gauge.observable.Set(f) +} \ No newline at end of file diff --git a/samples/krill/lib/gauge/gauge_test.go b/samples/krill/lib/gauge/gauge_test.go new file mode 100644 index 0000000..18c4355 --- /dev/null +++ b/samples/krill/lib/gauge/gauge_test.go @@ -0,0 +1,104 @@ +package gauge + +import ( + "testing" + + "github.com/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +const ( + name = "name" + label = "label" + invalid = "{}|}][" + invalidUTF8 = "\xc3\x28" +) + +func TestSimpleGaugeProvider(t *testing.T) { + registry := prometheus.NewRegistry() + + gaugeProvider, err := New(registry) + + require.NoError(t, err) + + gaugeProvider.Cancel() +} + +func TestGaugeProviderWithInvalidName(t *testing.T) { + registry := prometheus.NewRegistry() + + _, err := New(registry, func(cp *Provider) { + cp.Name = invalid + }) + + require.Equal(t, &InvalidPrometheusGaugeVecNameError{ + name: invalid, + }, err) +} + +func TestGaugeProviderWithDuplicateNames(t *testing.T) { + + registry := prometheus.NewRegistry() + + gaugeProvider, err := New(registry, func(cp *Provider) { + cp.Name = name + }) + + require.NoError(t, err) + + _, err = gaugeProvider.With(label) + + require.NoError(t, err) + + _, err = New(registry, func(cp *Provider) { + cp.Name = name + }) + + require.Equal(t, (&InvalidPrometheusGaugeVecNameError{ + name: name, + }).Error(), err.Error()) +} + +func TestGaugeWithLabel(t *testing.T) { + + registry := prometheus.NewRegistry() + + gaugeProvider, err := New(registry, func(cp *Provider) { + cp.Name = name + }) + + require.NoError(t, err) + + gauge, err := gaugeProvider.With(name) + + gauge.Observe(0) + gauge.Cancel() + + require.NoError(t, err) +} + +func TestGaugeWithLabelError(t *testing.T) { + + registry := prometheus.NewRegistry() + + gaugeProvider, err := New(registry, func(cp *Provider) { + cp.Name = name + }) + + require.NoError(t, err) + + _, err = gaugeProvider.With("") + + require.NoError(t, err) + + _, err = gaugeProvider.With(invalidUTF8) + + require.Equal(t, (&InvalidPrometheusGaugeLabelError{ + name: name, + label: invalidUTF8, + }).Error(), err.Error()) +} \ No newline at end of file diff --git a/samples/krill/lib/histogram/histogram.go b/samples/krill/lib/histogram/histogram.go new file mode 100644 index 0000000..8ce7eb6 --- /dev/null +++ b/samples/krill/lib/histogram/histogram.go @@ -0,0 +1,170 @@ +// Package histogram provides the histogram type implementation of the Provider interface. +// Histogram Providers represent the histogramVec prometheus metrics. +package histogram + +import ( + "fmt" + + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/lib/errors" + + "github.com/prometheus/client_golang/prometheus" +) + +// Provider is a registry.Provider implementation. +// Its purpose is to register a new prometheus histogramVec when created, +// And to create a histogram with a particular label when its with function is called. +type Provider struct { + HistogramVec *prometheus.HistogramVec + Name string + Help string + Label string + Start float64 + Width float64 + Buckets int + registry prometheus.Registerer +} + +const ( + SimulationHistogramDefaultName = "simulation_histogram" + SimulationHistogramDefaultHelp = "Simulation histogram" + SimulationHistogramDefaultBucketStart = 0 + SimulationHistogramDefaultBucketWidth = 1 + SimulationHistogramDefaultBucketCount = 1 + HistogramLabelKey = "histogram" +) + +type InvalidHistogramParametersError struct { + errors.BadRequest + buckets int + name string +} + +func (err *InvalidHistogramParametersError) Error() string { + return fmt.Sprintf( + "histogram provider with name %s had %d buckets specified, and there must be at least one bucket in a prometheus histogram", + err.name, + err.buckets, + ) +} + +type InvalidPrometheusHistogramVecNameError struct { + errors.BadRequest + name string +} + +func (err *InvalidPrometheusHistogramVecNameError) Error() string { + return fmt.Sprintf( + "could not create the histogram provider with the name %s because the name has already been registered or is invalid", + err.name, + ) +} + +type InvalidPrometheusHistogramLabelError struct { + errors.BadRequest + name string + label string +} + +func (err *InvalidPrometheusHistogramLabelError) Error() string { + return fmt.Sprintf( + "could not create the prometheus histogram with label %s from histogram provider %s because the label has already been used or is invalid", + err.label, + err.name, + ) +} + +// New creates a Provider, given a prometheus registerer. +// It can also take a function to set optional parameters. +func New( + reg prometheus.Registerer, + options ...func(*Provider), +) (*Provider, error) { + histogramProvider := &Provider{ + Name: SimulationHistogramDefaultName, + Help: SimulationHistogramDefaultHelp, + Start: SimulationHistogramDefaultBucketStart, + Width: SimulationHistogramDefaultBucketWidth, + Buckets: SimulationHistogramDefaultBucketCount, + Label: HistogramLabelKey, + registry: reg, + } + + for _, option := range options { + option(histogramProvider) + } + + if histogramProvider.Buckets <= 0 { + return nil, &InvalidHistogramParametersError{ + buckets: histogramProvider.Buckets, + name: histogramProvider.Name, + } + } + + histogramProvider.HistogramVec = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Name: histogramProvider.Name, + Help: histogramProvider.Help, + Buckets: prometheus.LinearBuckets( + histogramProvider.Start, + histogramProvider.Width, + histogramProvider.Buckets, + ), + }, + []string{histogramProvider.Label}, + ) + + err := reg.Register(histogramProvider.HistogramVec) + + if err != nil { + return nil, &InvalidPrometheusHistogramVecNameError{ + name: histogramProvider.Name, + } + } + + return histogramProvider, nil +} + +// Cancel unregisters the prometheus histogramVec from the prometheus registerer. +func (histogramProvider *Provider) Cancel() error { + histogramProvider.registry.Unregister(histogramProvider.HistogramVec) + return nil +} + +// With attempts to create a Histogram, which is a wrapper around the prometheus histogram metric that implements the CancellableObservable interface. +func (histogramProvider *Provider) With( + label string, +) (registry.CancellableObservable, error) { + histogram, err := histogramProvider.HistogramVec.GetMetricWith( + prometheus.Labels{histogramProvider.Label: label}, + ) + if err != nil { + return nil, &InvalidPrometheusHistogramLabelError{ + name: histogramProvider.Name, + label: label, + } + } + + return NewHistogram(histogram), nil +} + +// Histogram is an implementation of the CancellableObservable which wraps the functionality of the prometheus histogram metric. +// It observes a value into the prometheus histogram when its observe function is called. +type Histogram struct { + observable prometheus.Observer +} + +// NewHistogram creates a histogram given a prometheus histogram (in the form of an observable interface). +func NewHistogram(observable prometheus.Observer) *Histogram { + return &Histogram{ + observable: observable, + } +} + +// Observer calls the prometheus histograms observe function to observe a new value into the histogram. +func (histogram Histogram) Observe(value float64) { + histogram.observable.Observe(value) +} + +// Cancel is a no-op because a prometheus observable cannot be unregistered. +func (histogram Histogram) Cancel() {} \ No newline at end of file diff --git a/samples/krill/lib/histogram/histogram_test.go b/samples/krill/lib/histogram/histogram_test.go new file mode 100644 index 0000000..2a223fd --- /dev/null +++ b/samples/krill/lib/histogram/histogram_test.go @@ -0,0 +1,110 @@ +package histogram + +import ( + "testing" + + "github.com/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +const ( + name = "name" + label = "label" + invalid = "{}|}][" + invalidUTF8 = "\xc3\x28" +) + +func TestSimpleHistogramProvider(t *testing.T) { + registry := prometheus.NewRegistry() + + histogramProvider, err := New(registry) + + require.NoError(t, err) + + histogramProvider.Cancel() +} + +func TestHistogramProviderWithLabel(t *testing.T) { + registry := prometheus.NewRegistry() + + histogramProvider, err := New(registry, func(hp *Provider) { + hp.Name = name + }) + + require.NoError(t, err) + + histogram, err := histogramProvider.With(label) + + histogram.Observe(0) + histogram.Cancel() + + require.NoError(t, err) +} + +func TestHistogramProviderWithInvalidName(t *testing.T) { + registry := prometheus.NewRegistry() + + _, err := New(registry, func(hp *Provider) { + hp.Name = invalid + }) + + require.Equal(t, InvalidPrometheusHistogramVecNameError{ + name: invalid, + }, *err.(*InvalidPrometheusHistogramVecNameError)) +} + +func TestHistogramProviderWithInvalidBuckets(t *testing.T) { + registry := prometheus.NewRegistry() + buckets := -1 + + _, err := New(registry, func(hp *Provider) { + hp.Buckets = buckets + hp.Name = name + + }) + + require.Equal(t, &InvalidHistogramParametersError{ + buckets: buckets, + name: name, + }, err) +} + +func TestHistogramWithDuplicateNames(t *testing.T) { + registry := prometheus.NewRegistry() + + _, err := New(registry, func(hp *Provider) { + hp.Name = name + }) + + require.NoError(t, err) + + _, err = New(registry, func(hp *Provider) { + hp.Name = name + }) + + require.Equal(t, &InvalidPrometheusHistogramVecNameError{ + name: name, + }, err) +} + +func TestHistogramWithInvalidLabelName(t *testing.T) { + + registry := prometheus.NewRegistry() + + histogramProvider, err := New(registry, func(hp *Provider) { + hp.Name = name + }) + + require.NoError(t, err) + + _, err = histogramProvider.With(invalidUTF8) + + require.Equal(t, &InvalidPrometheusHistogramLabelError{ + name: name, + label: invalidUTF8, + }, err) +} \ No newline at end of file diff --git a/samples/krill/lib/krill/configuration.go b/samples/krill/lib/krill/configuration.go new file mode 100644 index 0000000..1a77867 --- /dev/null +++ b/samples/krill/lib/krill/configuration.go @@ -0,0 +1,138 @@ +package krill + +type ( + // Tag describes the structure of a simulated tag, including its ID, + // count (of how many instances of the tag to create), configuration (the equation which describes the behavior of this tag), + // and the missingChance (the percent chance that the tag will not be rendered). + Tag struct { + ID string `json:"id" yaml:"id"` + Configuration string `json:"configuration" yaml:"configuration"` + Count int `json:"count" yaml:"count"` + MissingChance int `json:"missingChance" yaml:"missingChance"` + } + + // Rate describes the flow of message publishes from the simulator, + // where limit describes the maximum number of services which leave the simulator over a period of PeriodSeconds. + // TagsPerMessage describes how many tags should be rendered per message sent. + Rate struct { + MessagesPerPeriod int `json:"messagesPerPeriod" yaml:"messagesPerPeriod"` + PeriodSeconds int `json:"periodSeconds" yaml:"periodSeconds"` + TagsPerMessage int `json:"tagsPerMessage" yaml:"tagsPerMessage"` + } + + // Site describes a logical collection of simulated devices. + Site struct { + // Name is the name of a site which will be used in creating topics for assets in this site. + Name string `json:"name" yaml:"name"` + + // Tags is a collection of tags which each asset in this site will send. + Tags []Tag `json:"tags" yaml:"tags"` + + // AssetCount is the number of total assets in this site, each represented by their own MQTT connection to the broker. + AssetCount int `json:"assetCount" yaml:"assetCount"` + + // Rate describes the flow of messages for each asset. + Rate Rate `json:"rate" yaml:"rate"` + + // PayloadFormat describes the shape of data sent by each asset (JSON, binary, CSV, etc.). + PayloadFormat string `json:"payloadFormat" yaml:"payloadFormat"` + + // TopicFormat describes the format of the template that each asset will publish messages on. + TopicFormat string `json:"topicFormat" yaml:"topicFormat"` + + // QoSLevel describes the QoS level of all message publishes by all assets. + QoSLevel int `json:"qosLevel" yaml:"qosLevel"` + + // MQTTVersion describes the MQTT protocol version to use for this site (v3 or v5). + MQTTVersion string `json:"mqttVersion" yaml:"mqttVersion"` + } + + // Target describes the target MQTT broker host and port. + Target struct { + Host string `json:"host" yaml:"host"` + Port int `json:"port" yaml:"port"` + } + + // Simulation describes the overall configuration for a simulation, including + // a collection of sites, a collection of refDatas, and an MQTT target. + Simulation struct { + Sites []Site `json:"sites" yaml:"sites"` + Target Target `json:"target" yaml:"target"` + } + + // Ports describes the ports of prometheus metrics data and the ref data application server. + Ports struct { + Metrics int `json:"metrics" yaml:"metrics"` + RefData int `json:"refData" yaml:"refData"` + } + + // Configuration describes the overall configuration structure for the krill simulator. + Configuration struct { + Simulation Simulation `json:"simulation" yaml:"simulation"` + Ports Ports `json:"ports" yaml:"ports"` + LogLevel int `json:"logLevel" yaml:"logLevel"` + } + + TopicTemplate struct { + SiteName string + AssetName string + TagName string + } +) + +const ( + BrokerID = "0" + ClientIDFormat = "%s__asset_%d" + TopicIDFormat = "%s__%s__%s" + TagIDFormat = "%s__%s__%d" + TagParentIDFormat = "%s__parent" + TagChildIDFormat = "%s__child" + ProviderIDFormat = "krill_%s_asset_publish_counter" + + TagTimestampIDFormat = "%s__timestamp" + OPCUATimeExpression = "now()" + OPCUATimeConfiguration = "Timestamp" + + TagSequenceIDFormat = "%s__sequence" + OPCUASequenceExpression = "x" + OPCUASequenceConfiguration = "SequenceNumber" + + TagDatasetWriterIDFormat = "%s__dataset_writer" + OPCUADatasetWriterExpression = `concat(site, concat("_", id))` + OPCUADatasetWriterConfiguration = "DataSetWriterName" + + TagPayloadIDFormat = "%s__payload" + OPCUAPayloadConfiguration = "Payload" + + TagValueIDFormat = "%s__value" + OPCUAValueConfiguration = "Value" + + TagSourceTimestampIDFormat = "%s__source_timestamp" + OPCUASourceTimeExpression = OPCUATimeExpression + OPCUASourceTimestampConfiguration = "SourceTimestamp" +) + +const ( + Krill = ` +⠀⠀⠀⠀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣤⣤⣀⠀⠀⠀⠀⠀⠀ +⠀⠀⢀⣀⡙⠻⢶⣶⣦⣴⣶⣶⣶⠾⠛⠛⠋⠉⠉⠉⠉⠙⠃⠀⠀⠀⠀⠀ +⠀⠀⠀⠉⠉⠙⠛⠛⠋⠉⠉⠡⣤⣴⣶⣶⣾⣿⣿⣿⣛⣩⣤⡤⠖⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⢠⣴⣾⠂⣴⣦⠈⣿⣿⣿⣿⣿⣿⠿⠛⣋⠁⠀⠀⠀⠀⠀ +⠀⠀⢀⣼⣿⣶⣄⡉⠻⣧⣌⣁⣴⣿⣿⣿⣿⣿⣿⡿⠛⠁⠀⠀⠀⠀⠀⠀ +⠀⠀⣾⣿⣿⣿⣿⣿⣦⡈⢻⣿⣿⣿⣿⡿⠿⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⡀⢻⣿⣿⣿⣿⣿⣿⣿⡄⠙⠛⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⢠⣷⣄⡉⠻⢿⣿⣿⣿⠏⠠⢶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⢸⣿⣿⣿⣶⣤⣈⠙⠁⠰⣦⣀⠉⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠘⢿⣿⣿⣿⣿⣿⡇⠠⣦⣄⠉⠳⣤⠈⠛⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⢠⣌⣉⡉⠉⣉⡁⠀⠀⠙⠗⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠹⢿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠙⠻⣿⣿⠟⢀⣤⡀⠀⠀⠀⠀⠀⠀⣀⣀⣠⣤⣤⣤⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠛⠿⠿⡿⠂⣀⣠⣤⣤⣤⣀⣉⣉⠉⠉⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠙⠛⠛⠛⠛⠋⠉⠉⠁⠀⠀⠀⠀ + _ _ _ _ + | |__ _ _ <_>| || | + | / /| '_>| || || | + |_\_\|_| |_||_||_| + +` +) diff --git a/samples/krill/lib/krill/krill.go b/samples/krill/lib/krill/krill.go new file mode 100644 index 0000000..c7d4009 --- /dev/null +++ b/samples/krill/lib/krill/krill.go @@ -0,0 +1,470 @@ +package krill + +import ( + "errors" + "fmt" + "io" + + "github.com/iot-for-all/device-simulation/components/broker" + "github.com/iot-for-all/device-simulation/components/client" + "github.com/iot-for-all/device-simulation/components/edge" + "github.com/iot-for-all/device-simulation/components/formatter" + "github.com/iot-for-all/device-simulation/components/limiter" + "github.com/iot-for-all/device-simulation/components/node" + "github.com/iot-for-all/device-simulation/components/observer" + "github.com/iot-for-all/device-simulation/components/outlet" + "github.com/iot-for-all/device-simulation/components/provider" + "github.com/iot-for-all/device-simulation/components/publisher" + "github.com/iot-for-all/device-simulation/components/registry" + "github.com/iot-for-all/device-simulation/components/renderer" + "github.com/iot-for-all/device-simulation/components/site" + "github.com/iot-for-all/device-simulation/components/subscriber" + "github.com/iot-for-all/device-simulation/components/topic" + "github.com/iot-for-all/device-simulation/components/tracer" + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/iot-for-all/device-simulation/lib/templater" +) + +type KrillBuilder struct { + broker component.Service[*broker.Component, component.ID] + client component.Service[*client.Component, component.ID] + edge component.Service[*edge.Component, component.ID] + formatter component.Service[*formatter.Component, component.ID] + limiter component.Service[*limiter.Component, component.ID] + node component.Service[*node.Component, component.ID] + observer component.Service[*observer.Component, component.ID] + outlet component.Service[*outlet.Component, component.ID] + provider component.Service[*provider.Component, component.ID] + publisher component.Service[*publisher.Component, component.ID] + registry component.Service[*registry.Component, component.ID] + renderer component.Service[*renderer.Component, component.ID] + site component.Service[*site.Component, component.ID] + subscriber component.Service[*subscriber.Component, component.ID] + topic component.Service[*topic.Component, component.ID] + tracer component.Service[*tracer.Component, component.ID] +} + +func New( + broker component.Service[*broker.Component, component.ID], + client component.Service[*client.Component, component.ID], + edge component.Service[*edge.Component, component.ID], + formatter component.Service[*formatter.Component, component.ID], + limiter component.Service[*limiter.Component, component.ID], + node component.Service[*node.Component, component.ID], + observer component.Service[*observer.Component, component.ID], + outlet component.Service[*outlet.Component, component.ID], + provider component.Service[*provider.Component, component.ID], + publisher component.Service[*publisher.Component, component.ID], + registry component.Service[*registry.Component, component.ID], + renderer component.Service[*renderer.Component, component.ID], + site component.Service[*site.Component, component.ID], + subscriber component.Service[*subscriber.Component, component.ID], + topic component.Service[*topic.Component, component.ID], + tracer component.Service[*tracer.Component, component.ID], +) *KrillBuilder { + return &KrillBuilder{ + broker: broker, + client: client, + edge: edge, + formatter: formatter, + limiter: limiter, + node: node, + observer: observer, + outlet: outlet, + provider: provider, + publisher: publisher, + registry: registry, + renderer: renderer, + site: site, + subscriber: subscriber, + topic: topic, + tracer: tracer, + } +} + +func (builder *KrillBuilder) Parse(configuration Simulation) error { + err := builder.broker.Create(BrokerID, &broker.Component{ + Broker: configuration.Target.Host, + Port: configuration.Target.Port, + }) + if err != nil { + return err + } + + for _, site := range configuration.Sites { + err := builder.ParseSite(site) + if err != nil { + return err + } + } + + return nil +} + +func (builder *KrillBuilder) ParseSite(configuration Site) error { + err := builder.site.Create(component.ID(configuration.Name), &site.Component{ + Name: configuration.Name, + }) + if err != nil { + return err + } + + tags, err := builder.ParseTags(configuration) + if err != nil { + return err + } + + err = builder.provider.Create(component.ID(configuration.Name), &provider.Component{ + Type: provider.COUNTER, + Name: fmt.Sprintf(ProviderIDFormat, configuration.Name), + }) + if err != nil { + return err + } + + assets, err := builder.ParseAssets(configuration) + if err != nil { + return err + } + + err = builder.ParseTopics(configuration, tags, assets) + if err != nil { + return err + } + + return nil +} + +func (builder *KrillBuilder) ParseTopics(configuration Site, tags []string, assets []string) error { + templateExecutor, err := templater.NewExecutor(configuration.TopicFormat) + if err != nil { + return err + } + + topicTemplate := templater.New[TopicTemplate](templateExecutor) + + for _, asset := range assets { + for _, tag := range tags { + topicID := fmt.Sprintf(TopicIDFormat, configuration.Name, asset, tag) + + reader, err := topicTemplate.Render(TopicTemplate{ + SiteName: configuration.Name, + AssetName: asset, + TagName: tag, + }) + if err != nil { + return err + } + + res, err := io.ReadAll(reader) + if err != nil { + return err + } + + err = builder.ParseTopicAndPublisher(configuration, topicID, string(res), asset, tag) + if err != nil { + return err + } + } + } + + return nil +} + +func (builder *KrillBuilder) ParseTopicAndPublisher(configuration Site, id string, name string, asset string, tag string) error { + err := builder.topic.Create(component.ID(id), &topic.Component{ + Name: name, + }) + if err != nil { + return err + } + + err = builder.limiter.Create(component.ID(id), &limiter.Component{ + Limit: configuration.Rate.MessagesPerPeriod, + PeriodSeconds: configuration.Rate.PeriodSeconds, + }) + if err != nil { + return err + } + + return builder.publisher.Create(component.ID(id), &publisher.Component{ + TopicID: component.ID(id), + ClientID: component.ID(asset), + RendererID: component.ID(tag), + QoSLevel: configuration.QoSLevel, + LimiterID: component.ID(id), + RendersPerPublish: configuration.Rate.TagsPerMessage, + }) +} + +func (builder *KrillBuilder) ParseTags(configuration Site) ([]string, error) { + switch configuration.PayloadFormat { + case "JSONTagPerMessage": + return builder.ParseJSONTagPerMessage(configuration) + case "JSON": + return builder.ParseComplex(configuration, formatter.JSON) + case "OPCUA": + return builder.ParseOPCUA(configuration) + case "BigEndian": + return builder.ParseFlat(configuration, "bigEndian") + case "LittleEndian": + return builder.ParseFlat(configuration, "littleEndian") + case "CSV": + return builder.ParseComplex(configuration, formatter.CSV) + case "Protobuf": + return builder.ParseComplex(configuration, formatter.PROTOBUF) + default: + return nil, errors.New("invalid payload format") + } +} + +func (builder *KrillBuilder) ParseAssets(configuration Site) ([]string, error) { + assets := make([]string, configuration.AssetCount) + for count := 0; count < configuration.AssetCount; count++ { + asset, err := builder.ParseAsset(configuration, count) + if err != nil { + return nil, err + } + assets[count] = asset + } + + return assets, nil +} + +func (builder *KrillBuilder) ParseAsset(configuration Site, count int) (string, error) { + clientID := fmt.Sprintf(ClientIDFormat, configuration.Name, count) + + err := builder.registry.Create(component.ID(clientID), ®istry.Component{}) + if err != nil { + return "", err + } + + err = builder.observer.Create(component.ID(clientID), &observer.Component{ + RegistryID: component.ID(clientID), + ProviderID: component.ID(configuration.Name), + Label: clientID, + }) + if err != nil { + return "", err + } + + err = builder.client.Create(component.ID(clientID), &client.Component{ + SiteID: component.ID(configuration.Name), + BrokerID: BrokerID, + Name: clientID, + Type: client.Type(configuration.MQTTVersion), + RegistryID: component.ID(clientID), + }) + if err != nil { + return "", err + } + + return clientID, nil +} + +func (builder *KrillBuilder) ParseJSONTagPerMessage(configuration Site) ([]string, error) { + err := builder.formatter.Create(component.ID(configuration.Name), &formatter.Component{ + Type: formatter.JSON, + }) + if err != nil { + return nil, err + } + + var tagNames []string + for _, tag := range configuration.Tags { + for count := 0; count < tag.Count; count++ { + tagName, err := builder.ParseJSONTag(configuration.Name, tag, count) + if err != nil { + return nil, err + } + tagNames = append(tagNames, tagName) + } + } + + return tagNames, nil +} + +func (builder *KrillBuilder) ParseJSONTag(siteName string, tag Tag, count int) (string, error) { + tagID := fmt.Sprintf(TagIDFormat, siteName, tag.ID, count) + childID := fmt.Sprintf(TagChildIDFormat, tagID) + + err := builder.ParseRootNode(siteName, tagID, node.COLLECTION) + if err != nil { + return "", err + } + + err = builder.ParseExpressionNode(tagID, childID, tagID, tag.Configuration, tagID, edge.LABEL) + if err != nil { + return "", err + } + + return tagID, nil +} + +func (builder *KrillBuilder) ParseOPCUA(configuration Site) ([]string, error) { + err := builder.ParseFormatter(configuration.Name, formatter.JSON, node.COLLECTION) + if err != nil { + return nil, err + } + + timestampID := fmt.Sprintf(TagTimestampIDFormat, configuration.Name) + + err = builder.ParseExpressionNode(configuration.Name, timestampID, timestampID, OPCUATimeExpression, OPCUATimeConfiguration, edge.LABEL) + if err != nil { + return nil, err + } + + sequenceID := fmt.Sprintf(TagSequenceIDFormat, configuration.Name) + + err = builder.ParseExpressionNode(configuration.Name, sequenceID, sequenceID, OPCUASequenceExpression, OPCUASequenceConfiguration, edge.LABEL) + if err != nil { + return nil, err + } + + datasetWriterID := fmt.Sprintf(TagDatasetWriterIDFormat, configuration.Name) + + err = builder.ParseExpressionNode(configuration.Name, datasetWriterID, datasetWriterID, OPCUADatasetWriterExpression, OPCUADatasetWriterConfiguration, edge.LABEL) + if err != nil { + return nil, err + } + + payloadID := fmt.Sprintf(TagPayloadIDFormat, configuration.Name) + + err = builder.ParseCollectionNode(configuration.Name, payloadID, payloadID, OPCUAPayloadConfiguration) + if err != nil { + return nil, err + } + + for _, tag := range configuration.Tags { + for count := 0; count < tag.Count; count++ { + err := builder.ParseOPCUATag(configuration, payloadID, tag, count) + if err != nil { + return nil, err + } + } + } + + return []string{configuration.Name}, nil +} + +func (builder *KrillBuilder) ParseOPCUATag(configuration Site, rootId string, tag Tag, count int) error { + tagID := fmt.Sprintf(TagIDFormat, configuration.Name, tag.ID, count) + + err := builder.ParseCollectionNode(rootId, tagID, tagID, tagID) + if err != nil { + return err + } + + valueID := fmt.Sprintf(TagValueIDFormat, tagID) + + err = builder.ParseExpressionNode(tagID, valueID, valueID, tag.Configuration, OPCUAValueConfiguration, edge.LABEL) + if err != nil { + return err + } + + sourceTimestampID := fmt.Sprintf(TagSourceTimestampIDFormat, tagID) + + return builder.ParseExpressionNode(tagID, sourceTimestampID, sourceTimestampID, OPCUASourceTimeExpression, OPCUASourceTimestampConfiguration, edge.LABEL) +} + +func (builder *KrillBuilder) ParseExpressionNode(rootNodeId, nodeId, edgeId, nodeExpression string, edgeConfiguration any, edgeType edge.Type) error { + err := builder.node.Create(component.ID(nodeId), &node.Component{ + Type: node.EXPRESSION, + Configuration: nodeExpression, + }) + if err != nil { + return err + } + + return builder.edge.Create(component.ID(edgeId), &edge.Component{ + ParentNodeId: component.ID(rootNodeId), + ChildNodeId: component.ID(nodeId), + Type: edgeType, + Configuration: edgeConfiguration, + }) +} + +func (builder *KrillBuilder) ParseCollectionNode(rootNodeId, nodeId, edgeId, edgeConfiguration string) error { + err := builder.node.Create(component.ID(nodeId), &node.Component{ + Type: node.COLLECTION, + }) + if err != nil { + return err + } + + return builder.edge.Create(component.ID(edgeId), &edge.Component{ + ParentNodeId: component.ID(rootNodeId), + ChildNodeId: component.ID(nodeId), + Type: edge.LABEL, + Configuration: edgeConfiguration, + }) +} + +func (builder *KrillBuilder) ParseComplex(configuration Site, format formatter.Type) ([]string, error) { + err := builder.ParseFormatter(configuration.Name, format, node.COLLECTION) + if err != nil { + return nil, err + } + + for _, tag := range configuration.Tags { + for count := 0; count < tag.Count; count++ { + tagID := fmt.Sprintf(TagIDFormat, configuration.Name, tag.ID, count) + + err := builder.ParseExpressionNode(configuration.Name, tagID, tagID, tag.Configuration, tagID, edge.LABEL) + if err != nil { + return nil, err + } + } + } + + return []string{configuration.Name}, nil +} + +func (builder *KrillBuilder) ParseFormatter(id string, format formatter.Type, nodeType node.Type) error { + err := builder.formatter.Create(component.ID(id), &formatter.Component{ + Type: format, + }) + if err != nil { + return err + } + + return builder.ParseRootNode(id, id, nodeType) +} + +func (builder *KrillBuilder) ParseRootNode(formatterID string, id string, nodeType node.Type) error { + err := builder.node.Create(component.ID(id), &node.Component{ + Type: nodeType, + }) + if err != nil { + return err + } + + return builder.renderer.Create(component.ID(id), &renderer.Component{ + FormatterID: component.ID(formatterID), + NodeID: component.ID(id), + }) +} + +func (builder *KrillBuilder) ParseFlat(configuration Site, format formatter.Type) ([]string, error) { + + err := builder.ParseFormatter(configuration.Name, format, node.ARRAY) + if err != nil { + return nil, err + } + + field := 0 + for _, tag := range configuration.Tags { + for count := 0; count < tag.Count; count++ { + tagID := fmt.Sprintf(TagIDFormat, configuration.Name, tag.ID, count) + + err := builder.ParseExpressionNode(configuration.Name, tagID, tagID, tag.Configuration, field, edge.POSITION) + if err != nil { + return nil, err + } + + field++ + } + } + + return []string{configuration.Name}, nil +} diff --git a/samples/krill/lib/krill/krill_test.go b/samples/krill/lib/krill/krill_test.go new file mode 100644 index 0000000..59e04dd --- /dev/null +++ b/samples/krill/lib/krill/krill_test.go @@ -0,0 +1,448 @@ +package krill + +import ( + "testing" + + "github.com/iot-for-all/device-simulation/components/edge" + "github.com/iot-for-all/device-simulation/components/formatter" + "github.com/iot-for-all/device-simulation/components/node" + "github.com/iot-for-all/device-simulation/components/renderer" + "github.com/iot-for-all/device-simulation/lib/component" + "github.com/stretchr/testify/require" +) + +var ( + MockKrillTag = Tag{ + ID: "float_1", + Configuration: "1", + Count: 1, + MissingChance: 0, + } + MockKrillRate = Rate{ + MessagesPerPeriod: 10, + PeriodSeconds: 1, + TagsPerMessage: 1, + } + MockKrillTarget = Target{ + Host: "localhost", + Port: 1883, + } + MockKrillSite = Site{ + Name: "site0", + Tags: []Tag{ + MockKrillTag, + }, + AssetCount: 1, + Rate: MockKrillRate, + PayloadFormat: "JSON", + TopicFormat: "{{.SiteName}}/{{.AssetName}}", + QoSLevel: 1, + MQTTVersion: "v5", + } + MockKrillConfiguration = Simulation{ + Sites: []Site{ + MockKrillSite, + }, + Target: MockKrillTarget, + } +) + +const ( + MockRootNodeID = "MockRootID" + MockChildNodeID = "MockChildNodeID" + MockEdgeID = "MockEdgeID" + MockNodeExpression = "MockNodeExpression" + MockEdgeConfiguration = "MockEdgeConfiguration" + MockEdgeType = edge.LABEL + MockFormatterID = "MockFormatterID" + MockFormatterType = formatter.BIG_ENDIAN + MockSiteName = "MockSiteName" + MockTagID = "MockTagID" + MockTagConfiguration = "MockTagConfiguration" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestParseExpressionNode(t *testing.T) { + builder := &KrillBuilder{ + node: &component.MockService[*node.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *node.Component) error { + require.Equal(t, MockChildNodeID, string(identifier)) + require.Equal(t, node.EXPRESSION, entity.Type) + require.Equal(t, MockNodeExpression, entity.Configuration) + return nil + }, + }, edge: &component.MockService[*edge.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *edge.Component) error { + require.Equal(t, MockEdgeID, string(identifier)) + require.Equal(t, MockRootNodeID, string(entity.ParentNodeId)) + require.Equal(t, MockChildNodeID, string(entity.ChildNodeId)) + require.Equal(t, MockEdgeType, entity.Type) + require.Equal(t, MockEdgeConfiguration, entity.Configuration) + return nil + }, + }, + } + + err := builder.ParseExpressionNode(MockRootNodeID, MockChildNodeID, MockEdgeID, MockNodeExpression, MockEdgeConfiguration, MockEdgeType) + require.NoError(t, err) +} + +func TestParseExpressionNodeNodeError(t *testing.T) { + builder := &KrillBuilder{ + node: &component.MockService[*node.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *node.Component) error { + return &component.MockError{} + }, + }, + } + + err := builder.ParseExpressionNode("", "", "", "", "", "") + require.Equal(t, &component.MockError{}, err) +} + +func TestParseCollectionNode(t *testing.T) { + builder := &KrillBuilder{ + node: &component.MockService[*node.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *node.Component) error { + require.Equal(t, MockChildNodeID, string(identifier)) + require.Equal(t, node.COLLECTION, entity.Type) + require.Equal(t, "", entity.Configuration) + return nil + }, + }, edge: &component.MockService[*edge.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *edge.Component) error { + require.Equal(t, MockEdgeID, string(identifier)) + require.Equal(t, MockRootNodeID, string(entity.ParentNodeId)) + require.Equal(t, MockChildNodeID, string(entity.ChildNodeId)) + require.Equal(t, edge.LABEL, entity.Type) + require.Equal(t, MockEdgeConfiguration, entity.Configuration) + return nil + }, + }, + } + + err := builder.ParseCollectionNode(MockRootNodeID, MockChildNodeID, MockEdgeID, MockEdgeConfiguration) + require.NoError(t, err) +} + +func TestParseCollectionNodeNodeError(t *testing.T) { + builder := &KrillBuilder{ + node: &component.MockService[*node.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *node.Component) error { + return &component.MockError{} + }, + }, + } + + err := builder.ParseCollectionNode("", "", "", "") + require.Equal(t, &component.MockError{}, err) +} + +func TestParseRootNode(t *testing.T) { + builder := &KrillBuilder{ + node: &component.MockService[*node.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *node.Component) error { + require.Equal(t, MockRootNodeID, string(identifier)) + require.Equal(t, node.COLLECTION, entity.Type) + require.Equal(t, "", entity.Configuration) + return nil + }, + }, renderer: &component.MockService[*renderer.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *renderer.Component) error { + require.Equal(t, MockRootNodeID, string(identifier)) + require.Equal(t, MockFormatterID, string(entity.FormatterID)) + require.Equal(t, MockRootNodeID, string(entity.NodeID)) + return nil + }, + }, + } + + err := builder.ParseRootNode(MockFormatterID, MockRootNodeID, node.COLLECTION) + require.NoError(t, err) +} + +func TestParseRootNodeNodeError(t *testing.T) { + builder := &KrillBuilder{ + node: &component.MockService[*node.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *node.Component) error { + return &component.MockError{} + }, + }, + } + + err := builder.ParseRootNode("", "", "") + require.Equal(t, &component.MockError{}, err) +} + +func TestParseFormatter(t *testing.T) { + builder := &KrillBuilder{ + formatter: &component.MockService[*formatter.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *formatter.Component) error { + require.Equal(t, MockFormatterID, string(identifier)) + require.Equal(t, MockFormatterType, entity.Type) + return nil + }, + }, + node: &component.MockService[*node.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *node.Component) error { + return nil + }, + }, renderer: &component.MockService[*renderer.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *renderer.Component) error { + return nil + }, + }, + } + + err := builder.ParseFormatter(MockFormatterID, MockFormatterType, "") + require.NoError(t, err) +} + +func TestParseFormatterError(t *testing.T) { + builder := &KrillBuilder{ + formatter: &component.MockService[*formatter.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *formatter.Component) error { + return &component.MockError{} + }, + }, + node: &component.MockService[*node.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *node.Component) error { + return nil + }, + }, renderer: &component.MockService[*renderer.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *renderer.Component) error { + return nil + }, + }, + } + + err := builder.ParseFormatter("", "", "") + require.Equal(t, &component.MockError{}, err) +} + +func TestParseFlat(t *testing.T) { + builder := &KrillBuilder{ + formatter: &component.MockService[*formatter.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *formatter.Component) error { + require.Equal(t, MockFormatterType, entity.Type) + require.Equal(t, MockSiteName, string(identifier)) + return nil + }, + }, + node: &component.MockService[*node.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *node.Component) error { + return nil + }, + }, edge: &component.MockService[*edge.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *edge.Component) error { + return nil + }, + }, renderer: &component.MockService[*renderer.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *renderer.Component) error { + return nil + }, + }, + } + + tags, err := builder.ParseFlat(Site{ + Name: MockSiteName, + Tags: []Tag{ + { + ID: MockTagID, + Configuration: MockTagConfiguration, + Count: 1, + }, + }, + }, MockFormatterType) + require.NoError(t, err) + require.Equal(t, []string{MockSiteName}, tags) +} + +func TestParseFlatFormatterError(t *testing.T) { + builder := &KrillBuilder{ + formatter: &component.MockService[*formatter.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *formatter.Component) error { + return &component.MockError{} + }, + }, + } + + _, err := builder.ParseFlat(Site{}, MockFormatterType) + require.Equal(t, &component.MockError{}, err) +} + +func TestParseFlatExpressionNodeError(t *testing.T) { + builder := &KrillBuilder{ + formatter: &component.MockService[*formatter.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *formatter.Component) error { + return nil + }, + }, + node: &component.MockService[*node.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *node.Component) error { + return nil + }, + }, edge: &component.MockService[*edge.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *edge.Component) error { + return &component.MockError{} + }, + }, renderer: &component.MockService[*renderer.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *renderer.Component) error { + return nil + }, + }, + } + + _, err := builder.ParseFlat(Site{ + Name: MockSiteName, + Tags: []Tag{ + { + Count: 1, + }, + }, + }, MockFormatterType) + require.Equal(t, &component.MockError{}, err) +} + +func TestParseJSONTag(t *testing.T) { + builder := &KrillBuilder{ + node: &component.MockService[*node.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *node.Component) error { + return nil + }, + }, edge: &component.MockService[*edge.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *edge.Component) error { + require.Equal(t, "MockSiteName__MockTagID__0__child", string(entity.ChildNodeId)) + return nil + }, + }, renderer: &component.MockService[*renderer.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *renderer.Component) error { + return nil + }, + }, + } + + res, err := builder.ParseJSONTag(MockSiteName, Tag{ + Count: 1, + ID: MockTagID, + }, 0) + require.NoError(t, err) + require.Equal(t, "MockSiteName__MockTagID__0", res) +} + +func TestParseJSONTagRootNodeError(t *testing.T) { + builder := &KrillBuilder{ + node: &component.MockService[*node.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *node.Component) error { + return &component.MockError{} + }, + }, renderer: &component.MockService[*renderer.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *renderer.Component) error { + return nil + }, + }, + } + + _, err := builder.ParseJSONTag(MockSiteName, Tag{}, 0) + require.Equal(t, &component.MockError{}, err) +} + +func TestParseJSONTagExpressionNodeError(t *testing.T) { + builder := &KrillBuilder{ + node: &component.MockService[*node.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *node.Component) error { + return nil + }, + }, edge: &component.MockService[*edge.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *edge.Component) error { + return &component.MockError{} + }, + }, renderer: &component.MockService[*renderer.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *renderer.Component) error { + return nil + }, + }, + } + + _, err := builder.ParseJSONTag(MockSiteName, Tag{}, 0) + require.Equal(t, &component.MockError{}, err) +} + +func TestParseJSONTagPerMessage(t *testing.T) { + builder := &KrillBuilder{ + formatter: &component.MockService[*formatter.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *formatter.Component) error { + require.Equal(t, MockSiteName, string(identifier)) + require.Equal(t, formatter.JSON, entity.Type) + return nil + }, + }, + node: &component.MockService[*node.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *node.Component) error { + return nil + }, + }, edge: &component.MockService[*edge.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *edge.Component) error { + return nil + }, + }, renderer: &component.MockService[*renderer.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *renderer.Component) error { + return nil + }, + }, + } + + tags, err := builder.ParseJSONTagPerMessage(Site{ + Name: MockSiteName, + Tags: []Tag{ + { + ID: MockTagID, + Count: 1, + }, + }, + }) + require.NoError(t, err) + require.Equal(t, []string{"MockSiteName__MockTagID__0"}, tags) +} + +func TestParseJSONTagPerMessageFormatterError(t *testing.T) { + builder := &KrillBuilder{ + formatter: &component.MockService[*formatter.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *formatter.Component) error { + return &component.MockError{} + }, + }, + } + + _, err := builder.ParseJSONTagPerMessage(Site{}) + require.Equal(t, &component.MockError{}, err) +} + +func TestParseJSONTagPerMessageParseJSONTagError(t *testing.T) { + builder := &KrillBuilder{ + formatter: &component.MockService[*formatter.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *formatter.Component) error { + return nil + }, + }, + node: &component.MockService[*node.Component, component.ID]{ + OnCreate: func(identifier component.ID, entity *node.Component) error { + return &component.MockError{} + }, + }, + } + + _, err := builder.ParseJSONTagPerMessage(Site{ + Name: MockSiteName, + Tags: []Tag{ + { + ID: MockTagID, + Count: 1, + }, + }, + }) + require.Equal(t, &component.MockError{}, err) +} \ No newline at end of file diff --git a/samples/krill/lib/logger/logger.go b/samples/krill/lib/logger/logger.go new file mode 100644 index 0000000..e750d51 --- /dev/null +++ b/samples/krill/lib/logger/logger.go @@ -0,0 +1,210 @@ +// Package logger provides all logging functionality for the simulation framework. +package logger + +import ( + "fmt" + + "github.com/rs/zerolog" +) + +// Level provides the String function which converts an int-based level into a string representation. +type Level struct{} + +const ( + Trace int = iota + Debug + Info + Warn + Critical + Error + Fatal + Panic +) + +const ( + levelName = "level" +) + +// String converts a given integer level to a string representation. +// It is meant to be used with the iota enumeration defined above. +func (l *Level) String(level int) string { + switch level { + case Trace: + return "trace" + case Debug: + return "debug" + case Info: + return "info" + case Warn: + return "warn" + case Critical: + return "critical" + case Error: + return "error" + case Fatal: + return "fatal" + case Panic: + return "panic" + default: + return "no_level_defined" + } +} + +// LevelString is an interface whose implementation should convert an integer based log level to a string. +type LevelString interface { + String(int) string +} + +// Logger is an interface whose implementation should be able to print logs and enrich these logs with level information and custom key-value pair fields. +type Logger interface { + Println(v ...interface{}) + Printf(format string, v ...interface{}) + Level(l int) Logger + With(k, v string) Logger + Tag(t string) Logger +} + +// ZeroLoggerWrapper is a Logger implementation which wraps the logging functionality of the zero-log library. +// It also uses a LevelString implementation to convert numerical log levels to strings which can be logged. +type ZeroLoggerWrapper struct { + logger zerolog.Logger + Levels LevelString + LogLevel int + Tags string +} + +// NewZeroLoggerWrapper creates a new ZeroLoggerWrapper given a zerolog logger. +// Optional parameters (LevelString implementation and LogLevel) can be set using the options function. +func NewZeroLoggerWrapper( + logger zerolog.Logger, + options ...func(*ZeroLoggerWrapper), +) *ZeroLoggerWrapper { + wrapper := &ZeroLoggerWrapper{ + logger: logger, + Levels: &Level{}, + } + + for _, option := range options { + option(wrapper) + } + + return wrapper +} + +// Level creates a new ZeroLoggerWrapper whose logs will all contain the level field defined by the provided level. +// If the level is not above the originally specified log level, a noop logger will be returned. +func (loggerWrapper *ZeroLoggerWrapper) Level(l int) Logger { + if l < loggerWrapper.LogLevel { + return &NoopLogger{} + } + + return &ZeroLoggerWrapper{ + logger: loggerWrapper.logger.With(). + Str(levelName, loggerWrapper.Levels.String(l)). + Logger(), + Levels: loggerWrapper.Levels, + LogLevel: loggerWrapper.LogLevel, + Tags: loggerWrapper.Tags, + } +} + +// With enriches the current logger with a new key value pair, and returns a new ZeroLoggerWrapper. +func (loggerWrapper *ZeroLoggerWrapper) With(k, v string) Logger { + return &ZeroLoggerWrapper{ + logger: loggerWrapper.logger.With().Str(k, v).Logger(), + Levels: loggerWrapper.Levels, + LogLevel: loggerWrapper.LogLevel, + Tags: loggerWrapper.Tags, + } +} + +func (loggerWrapper *ZeroLoggerWrapper) Tag(t string) Logger { + if loggerWrapper.Tags == "" { + return &ZeroLoggerWrapper{ + logger: loggerWrapper.logger, + Levels: loggerWrapper.Levels, + LogLevel: loggerWrapper.LogLevel, + Tags: `"` + t + `"`, + } + } + return &ZeroLoggerWrapper{ + logger: loggerWrapper.logger, + Levels: loggerWrapper.Levels, + LogLevel: loggerWrapper.LogLevel, + Tags: loggerWrapper.Tags + `,"` + t + `"`, + } +} + +// Printf converts a format string using Sprintf and then logs this as the message field in the zerolog logger. +func (loggerWrapper *ZeroLoggerWrapper) Printf( + format string, + v ...interface{}, +) { + loggerWrapper.logger.Log().RawJSON("tags", []byte("[" + loggerWrapper.Tags + "]")).Msg(fmt.Sprintf(format, v...)) +} + +// Println applies a Sprintln to provided parameters and then logs this as a message field in the zerolog logger. +func (loggerWrapper *ZeroLoggerWrapper) Println(v ...interface{}) { + loggerWrapper.logger.Log().RawJSON("tags", []byte("[" + loggerWrapper.Tags + "]")).Msg(fmt.Sprintln(v...)) +} + +// NoopLogger is a Logger implementation with Noop functionality. +// From a performance perspective, it makes the most sense to perform logging this way, +// as the compiler will optimize noop function calls under the hood. +type NoopLogger struct { +} + +// Println is a noop. +func (*NoopLogger) Println(...interface{}) { +} + +// Printf is a noop. +func (*NoopLogger) Printf(string, ...interface{}) { +} + +// Level returns the noop logger. +func (l *NoopLogger) Level(int) Logger { + return l +} + +// With returns the noop logger. +func (l *NoopLogger) With(string, string) Logger { + return l +} + +func (l *NoopLogger) Tag(t string) Logger { + return l +} + +// MockLogger is a mock logger implementation to be used in testing scenarios. +type MockLogger struct { + OnPrintln func(...interface{}) + OnPrintf func(string, ...interface{}) + OnLevel func(int) Logger + OnWith func(string, string) Logger + OnTag func(string) Logger +} + +// Println calls the mock logger's OnPrintln function, passing through its parameters. +func (l *MockLogger) Println(s ...interface{}) { + l.OnPrintln(s...) +} + +// Printf calls the mock logger's OnPrintf function, passing through its parameters. +func (l *MockLogger) Printf(s string, ls ...interface{}) { + l.OnPrintf(s, ls...) +} + +// Level calls the mock logger's OnLevel function, passing through its parameters. +func (l *MockLogger) Level(i int) Logger { + return l.OnLevel(i) +} + +// With calls the mock logger's OnWith function, passing through its parameters. +func (l *MockLogger) With(k string, v string) Logger { + return l.OnWith(k, v) +} + +func (l *MockLogger) Tag(t string) Logger { + return l.OnTag(t) +} diff --git a/samples/krill/lib/logger/logger_test.go b/samples/krill/lib/logger/logger_test.go new file mode 100644 index 0000000..6531494 --- /dev/null +++ b/samples/krill/lib/logger/logger_test.go @@ -0,0 +1,44 @@ +package logger + +import ( + "testing" + + "github.com/rs/zerolog/log" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestZeroLoggerWrapper(t *testing.T) { + wrappedLogger := NewZeroLoggerWrapper(log.With().Logger()) + wrappedLogger.Printf("") + wrappedLogger.Println("") +} + +func TestNoopLogger(t *testing.T) { + logger := &NoopLogger{} + logger.Printf("") + logger.Println("") + logger.With("", "") + logger.Level(0) +} + +func TestMockLogger(t *testing.T) { + logger := &MockLogger{ + OnPrintln: func(...interface{}) { + }, + OnPrintf: func(string, ...interface{}) { + }, + OnLevel: func(int) Logger { + return nil + }, + OnWith: func(string, string) Logger { + return nil + }, + } + logger.Printf("") + logger.Println("") + logger.With("", "") + logger.Level(0) +} \ No newline at end of file diff --git a/samples/krill/lib/proto/gen.sh b/samples/krill/lib/proto/gen.sh new file mode 100755 index 0000000..6e4f96e --- /dev/null +++ b/samples/krill/lib/proto/gen.sh @@ -0,0 +1,3 @@ +protoc --go_out=. --go_opt=paths=source_relative \ + --go-grpc_out=require_unimplemented_servers=false:. --go-grpc_opt=paths=source_relative \ + message.proto \ No newline at end of file diff --git a/samples/krill/lib/proto/message.pb.go b/samples/krill/lib/proto/message.pb.go new file mode 100644 index 0000000..dd3656d --- /dev/null +++ b/samples/krill/lib/proto/message.pb.go @@ -0,0 +1,246 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v3.6.1 +// source: message.proto + +package proto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Message struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Options: + // + // *Message_String_ + // *Message_Integer + // *Message_Float + // *Message_Boolean + Options isMessage_Options `protobuf_oneof:"options"` + Map map[string]*Message `protobuf:"bytes,5,rep,name=map,proto3" json:"map,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Array []*Message `protobuf:"bytes,6,rep,name=array,proto3" json:"array,omitempty"` +} + +func (x *Message) Reset() { + *x = Message{} + if protoimpl.UnsafeEnabled { + mi := &file_message_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Message) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Message) ProtoMessage() {} + +func (x *Message) ProtoReflect() protoreflect.Message { + mi := &file_message_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Message.ProtoReflect.Descriptor instead. +func (*Message) Descriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{0} +} + +func (m *Message) GetOptions() isMessage_Options { + if m != nil { + return m.Options + } + return nil +} + +func (x *Message) GetString_() string { + if x, ok := x.GetOptions().(*Message_String_); ok { + return x.String_ + } + return "" +} + +func (x *Message) GetInteger() int32 { + if x, ok := x.GetOptions().(*Message_Integer); ok { + return x.Integer + } + return 0 +} + +func (x *Message) GetFloat() float64 { + if x, ok := x.GetOptions().(*Message_Float); ok { + return x.Float + } + return 0 +} + +func (x *Message) GetBoolean() bool { + if x, ok := x.GetOptions().(*Message_Boolean); ok { + return x.Boolean + } + return false +} + +func (x *Message) GetMap() map[string]*Message { + if x != nil { + return x.Map + } + return nil +} + +func (x *Message) GetArray() []*Message { + if x != nil { + return x.Array + } + return nil +} + +type isMessage_Options interface { + isMessage_Options() +} + +type Message_String_ struct { + String_ string `protobuf:"bytes,1,opt,name=string,proto3,oneof"` +} + +type Message_Integer struct { + Integer int32 `protobuf:"varint,2,opt,name=integer,proto3,oneof"` +} + +type Message_Float struct { + Float float64 `protobuf:"fixed64,3,opt,name=float,proto3,oneof"` +} + +type Message_Boolean struct { + Boolean bool `protobuf:"varint,4,opt,name=boolean,proto3,oneof"` +} + +func (*Message_String_) isMessage_Options() {} + +func (*Message_Integer) isMessage_Options() {} + +func (*Message_Float) isMessage_Options() {} + +func (*Message_Boolean) isMessage_Options() {} + +var File_message_proto protoreflect.FileDescriptor + +var file_message_proto_rawDesc = []byte{ + 0x0a, 0x0d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0x85, 0x02, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x06, 0x73, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x73, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x1a, 0x0a, 0x07, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x07, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, + 0x72, 0x12, 0x16, 0x0a, 0x05, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, + 0x48, 0x00, 0x52, 0x05, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x12, 0x1a, 0x0a, 0x07, 0x62, 0x6f, 0x6f, + 0x6c, 0x65, 0x61, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x07, 0x62, 0x6f, + 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x12, 0x23, 0x0a, 0x03, 0x6d, 0x61, 0x70, 0x18, 0x05, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x03, 0x6d, 0x61, 0x70, 0x12, 0x1e, 0x0a, 0x05, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x05, 0x61, 0x72, 0x72, 0x61, 0x79, 0x1a, 0x40, 0x0a, 0x08, 0x4d, 0x61, + 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x09, 0x0a, 0x07, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x6f, 0x74, 0x2d, 0x66, 0x6f, 0x72, 0x2d, 0x61, 0x6c, + 0x6c, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2d, 0x73, 0x69, 0x6d, 0x75, 0x6c, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_message_proto_rawDescOnce sync.Once + file_message_proto_rawDescData = file_message_proto_rawDesc +) + +func file_message_proto_rawDescGZIP() []byte { + file_message_proto_rawDescOnce.Do(func() { + file_message_proto_rawDescData = protoimpl.X.CompressGZIP(file_message_proto_rawDescData) + }) + return file_message_proto_rawDescData +} + +var file_message_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_message_proto_goTypes = []interface{}{ + (*Message)(nil), // 0: Message + nil, // 1: Message.MapEntry +} +var file_message_proto_depIdxs = []int32{ + 1, // 0: Message.map:type_name -> Message.MapEntry + 0, // 1: Message.array:type_name -> Message + 0, // 2: Message.MapEntry.value:type_name -> Message + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_message_proto_init() } +func file_message_proto_init() { + if File_message_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_message_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Message); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_message_proto_msgTypes[0].OneofWrappers = []interface{}{ + (*Message_String_)(nil), + (*Message_Integer)(nil), + (*Message_Float)(nil), + (*Message_Boolean)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_message_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_message_proto_goTypes, + DependencyIndexes: file_message_proto_depIdxs, + MessageInfos: file_message_proto_msgTypes, + }.Build() + File_message_proto = out.File + file_message_proto_rawDesc = nil + file_message_proto_goTypes = nil + file_message_proto_depIdxs = nil +} diff --git a/samples/krill/lib/proto/message.proto b/samples/krill/lib/proto/message.proto new file mode 100644 index 0000000..a7af10d --- /dev/null +++ b/samples/krill/lib/proto/message.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; +option go_package = "github.com/iot-for-all/device-simulation/lib/proto"; + +message Message { + oneof options { + string string = 1; + int32 integer = 2; + double float = 3; + bool boolean = 4; + } + map map = 5; + repeated Message array = 6; +} \ No newline at end of file diff --git a/samples/krill/lib/proto/proto.go b/samples/krill/lib/proto/proto.go new file mode 100644 index 0000000..6328000 --- /dev/null +++ b/samples/krill/lib/proto/proto.go @@ -0,0 +1,100 @@ +package proto + +type Encoder interface { + Encode(any) *Message + Decode(*Message) any +} + +type ProtoEncoder struct { +} + +func New() *ProtoEncoder { + return &ProtoEncoder{} +} + +func (encoder *ProtoEncoder) Encode(message any) *Message { + + res := new(Message) + + switch option := message.(type) { + case []any: + for _, element := range option { + res.Array = append(res.Array, encoder.Encode(element)) + } + case map[string]any: + + res.Map = make(map[string]*Message) + + for k, v := range option { + res.Map[k] = encoder.Encode(v) + } + case int: + res.Options = &Message_Integer{ + Integer: int32(option), + } + case float64: + res.Options = &Message_Float{ + Float: option, + } + case string: + res.Options = &Message_String_{ + String_: option, + } + case bool: + res.Options = &Message_Boolean{ + Boolean: option, + } + } + + return res +} + +func (encoder *ProtoEncoder) Decode(message *Message) any { + + if len(message.Array) > 0 { + + res := make([]any, len(message.Array)) + + for idx, element := range message.Array { + res[idx] = encoder.Decode(element) + } + + return res + } + + if len(message.Map) > 0 { + res := make(map[string]any) + + for k, v := range message.Map { + res[k] = encoder.Decode(v) + } + + return res + } + + switch option := message.Options.(type) { + case *Message_String_: + return option.String_ + case *Message_Integer: + return int(option.Integer) + case *Message_Float: + return option.Float + case *Message_Boolean: + return option.Boolean + } + + return nil +} + +type MockEncoder struct { + OnEncode func(any) *Message + OnDecode func(*Message) any +} + +func (encoder *MockEncoder) Encode(a any) *Message { + return encoder.OnEncode(a) +} + +func (encoder *MockEncoder) Decode(a *Message) any { + return encoder.OnDecode(a) +} diff --git a/samples/krill/lib/proto/proto_test.go b/samples/krill/lib/proto/proto_test.go new file mode 100644 index 0000000..6966413 --- /dev/null +++ b/samples/krill/lib/proto/proto_test.go @@ -0,0 +1,36 @@ +package proto + +import ( + "testing" + + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" +) + +func TestMain(m *testing.M) { + m.Run() +} + +func TestProtoEncodingAndDecoding(t *testing.T) { + encoder := New() + + original := map[string]any{ + "my_arr": []any{"1", 2, 3.0, true}, + "my_map": map[string]any{"hello": "hello", "hello-1": 1}, + "my_elem": 66.0, + } + + message := encoder.Encode(original) + + b, err := proto.Marshal(message) + require.NoError(t, err) + + res := new(Message) + + err = proto.Unmarshal(b, res) + require.NoError(t, err) + + decoded := encoder.Decode(res) + + require.Equal(t, original, decoded) +} diff --git a/samples/krill/lib/templater/templater.go b/samples/krill/lib/templater/templater.go new file mode 100755 index 0000000..7021fc1 --- /dev/null +++ b/samples/krill/lib/templater/templater.go @@ -0,0 +1,85 @@ +// Package templater contains the templating functionality used to convert a general request body template into a body specific to a particular request. +package templater + +import ( + "bytes" + "io" + "text/template" +) + +// TemplateRenderer is an interface with a Render method. +// Render converts a generic to an io.Reader, or an error. +type TemplateRenderer[T any] interface { + Render(vars T) (io.Reader, error) +} + +type TemplateExecuter interface { + Execute(wr io.Writer, data any) error +} + +type Executor struct { + *template.Template +} + +func NewExecutor(content string) (*Executor, error) { + templ, err := template.New("").Parse(content) + if err != nil { + return nil, err + } + return &Executor{ + templ, + }, nil +} + +// Templater is a wrapper struct around the functionality of the golang wrapper. +type Templater[T any] struct { + template TemplateExecuter +} + +// New creates a new Templater. +// It must be given a template in the form of a string as a parameter. +func New[T any](templ TemplateExecuter) *Templater[T] { + return &Templater[T]{ + template: templ, + } +} + +// Render converts a template into an io.Reader (which can be further reduced to string) given variables specific to that template. +func (templater *Templater[T]) Render(vars T) (io.Reader, error) { + var buffer bytes.Buffer + err := templater.template.Execute(&buffer, vars) + if err != nil { + return nil, err + } + + return &buffer, nil +} + +type NoopReader struct{} + +func (*NoopReader) Read([]byte) (int, error) { return 0, io.EOF } +func (*NoopReader) Close() error { return nil } +func (*NoopReader) WriteTo(io.Writer) (int64, error) { return 0, nil } + +type NoopRenderer[T any] struct { +} + +func (renderer *NoopRenderer[T]) Render(vars T) (io.Reader, error) { + return &NoopReader{}, nil +} + +type MockRenderer[T any] struct { + OnRender func(vars T) (io.Reader, error) +} + +func (renderer *MockRenderer[T]) Render(vars T) (io.Reader, error) { + return renderer.OnRender(vars) +} + +type MockExecutor struct { + OnExecute func(wr io.Writer, data any) error +} + +func (executor *MockExecutor) Execute(wr io.Writer, data any) error { + return executor.OnExecute(wr, data) +} \ No newline at end of file diff --git a/samples/krill/lib/templater/templater_test.go b/samples/krill/lib/templater/templater_test.go new file mode 100755 index 0000000..f94bc73 --- /dev/null +++ b/samples/krill/lib/templater/templater_test.go @@ -0,0 +1,105 @@ +package templater + +import ( + "io" + "testing" + "text/template" + + "github.com/iot-for-all/device-simulation/lib/errors" + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + m.Run() +} + +type MockType struct { + ID string +} + +var ( + example = `{"id": {{ .ID }}}` + expected = `{"id": 1}` + id = "1" +) + +func TestTemplater(t *testing.T) { + templ, err := template.New("").Parse(example) + require.NoError(t, err) + + templater := New[MockType](templ) + reader, err := templater.Render(MockType{ + ID: id, + }) + require.NoError(t, err) + + res, err := io.ReadAll(reader) + require.NoError(t, err) + + require.Equal(t, expected, string(res)) +} + +func TestTemplaterRenderError(t *testing.T) { + + templater := New[MockType](&MockExecutor{ + OnExecute: func(wr io.Writer, data any) error { + return errors.Mock{} + }, + }) + _, err := templater.Render(MockType{ + ID: id, + }) + require.Equal(t, errors.Mock{}, err) +} + +func TestNoopRenderer(t *testing.T) { + noopRenderer := &NoopRenderer[MockType]{} + reader, err := noopRenderer.Render(MockType{}) + require.NoError(t, err) + require.Equal(t, &NoopReader{}, reader) +} + +func TestNoopReader(t *testing.T) { + reader := &NoopReader{} + + readRes, err := reader.Read(nil) + require.Equal(t, 0, readRes) + require.Equal(t, io.EOF, err) + + require.NoError(t, reader.Close()) + + writeRes, err := reader.WriteTo(nil) + require.Equal(t, int64(0), writeRes) + require.NoError(t, err) +} + +func TestMockRenderer(t *testing.T) { + mockRenderer := &MockRenderer[MockType]{ + OnRender: func(vars MockType) (io.Reader, error) { + return nil, errors.Mock{} + }, + } + + _, err := mockRenderer.Render(MockType{}) + require.Equal(t, errors.Mock{}, err) +} + +func TestMockExecutor(t *testing.T) { + mockExecutor := &MockExecutor{ + OnExecute: func(wr io.Writer, data any) error { + return errors.Mock{} + }, + } + + require.Equal(t, errors.Mock{}, mockExecutor.Execute(nil, nil)) +} + +func TestExecutor(t *testing.T) { + _, err := NewExecutor("") + require.NoError(t, err) +} + +func TestExecutorParseError(t *testing.T) { + _, err := NewExecutor("{{{}}") + require.Error(t, err) +} \ No newline at end of file diff --git a/scripts/arcConnect.sh b/scripts/arcConnect.sh new file mode 100644 index 0000000..d69d863 --- /dev/null +++ b/scripts/arcConnect.sh @@ -0,0 +1,129 @@ +#!/bin/bash + +# Function to print in green +print_green() { + echo -e "\033[32m$1\033[0m" +} + + +# Fetch the currently active subscription +echo -e "\nFetching the currently active subscription..." +CURRENT_SUBSCRIPTION=$(az account show --query "name" -o tsv 2>/dev/null) +if [ -z "$CURRENT_SUBSCRIPTION" ]; then + echo -e "\nError: Failed to fetch the currently active Azure subscription. Please run 'az login' to set up an account.\n" + exit 1 +fi + +echo -e "\n" +read -p "Is \"$(print_green "$CURRENT_SUBSCRIPTION")\" the right subscription to use? (y/n): " RESPONSE +echo -e "\n" + +if [[ "$RESPONSE" != "y" ]]; then + echo -e "Please use 'az account set' command to set the right subscription and then rerun the script.\n" + exit 1 +fi + +# Default values +DEFAULT_LOCATION="westus3" +DEFAULT_RESOURCE_GROUP="$CODESPACE_NAME" +CLUSTER_NAME="iotops-quickstart-cluster" +SUPPORTED_LOCATIONS=("eastus" "eastus2" "westus2" "westus3") + +# Ask the user if they want to provide their own values +echo -e "\n" +read -p "Do you want to provide your own values for location and resource group? (y/n): " CUSTOM_VALUES +echo -e "\n" + +if [[ "$CUSTOM_VALUES" == "y" ]]; then + # User provides their own values + while true; do + read -p "Enter the resource group name: " RESOURCE_GROUP + + # Check if the provided resource group exists + echo -e "\nChecking if the resource group $RESOURCE_GROUP exists..." + az group show --name $RESOURCE_GROUP &> /dev/null + if [ $? -eq 0 ]; then + # Resource group exists, check if it's in a supported location + echo -e "\nChecking the location of the resource group $RESOURCE_GROUP..." + RG_LOCATION=$(az group show --name $RESOURCE_GROUP --query "location" -o tsv) + if [[ " ${SUPPORTED_LOCATIONS[@]} " =~ " ${RG_LOCATION} " ]]; then + LOCATION=$RG_LOCATION + break + else + echo -e "\nError: The resource group $RESOURCE_GROUP exists but is not in a supported location. Supported locations are: ${SUPPORTED_LOCATIONS[*]}.\n" + read -p "Do you want to specify a different resource group and location? (y/n): " TRY_AGAIN + if [[ "$TRY_AGAIN" != "y" ]]; then + exit 1 + fi + fi + else + # Resource group does not exist, ask for location and create it + while true; do + read -p "Enter the location (Supported: eastus, eastus2, westus2, westus3): " LOCATION + if [[ " ${SUPPORTED_LOCATIONS[@]} " =~ " ${LOCATION} " ]]; then + break + else + echo -e "\nError: The location $LOCATION is not supported. Please choose from eastus, eastus2, westus2, or westus3.\n" + fi + done + echo -e "\nCreating resource group $RESOURCE_GROUP in location $LOCATION..." + az group create --name $RESOURCE_GROUP --location $LOCATION --output table + if [ $? -ne 0 ]; then + echo -e "\nError: Failed to create the resource group.\n" + exit 1 + fi + break + fi + done +else + # User chooses to use default values + RESOURCE_GROUP=$DEFAULT_RESOURCE_GROUP + LOCATION=$DEFAULT_LOCATION + + # Check if the default resource group exists and create it if it doesn’t + echo -e "\nChecking if the default resource group $RESOURCE_GROUP exists..." + az group show --name $RESOURCE_GROUP &> /dev/null + if [ $? -ne 0 ]; then + echo -e "\nCreating default resource group $RESOURCE_GROUP in location $LOCATION..." + az group create --name $RESOURCE_GROUP --location $LOCATION --output table + if [ $? -ne 0 ]; then + echo -e "\nError: Failed to create the default resource group.\n" + exit 1 + fi + fi +fi +# Add the connectedk8s extension +echo -e "\nAdding the connectedk8s extension..." +az extension add --name connectedk8s +if [ $? -ne 0 ]; then + echo -e "\nError: Failed to add the connectedk8s extension.\n" + exit 1 +fi + +# Connect the Kubernetes cluster to Azure Arc +echo -e "\nConnecting the Kubernetes cluster to Azure Arc..." +az connectedk8s connect --name $CLUSTER_NAME --resource-group $RESOURCE_GROUP +if [ $? -ne 0 ]; then + echo -e "\nError: Failed to connect the Kubernetes cluster to Azure Arc.\n" + exit 1 +else + + # After the connection to Azure Arc + echo -e "\nTo manually export the cluster name and resource group for later use, run the following commands in your terminal:\n" + echo -e "$(print_green "export CLUSTER_NAME=$CLUSTER_NAME")" + echo -e "$(print_green "export RESOURCE_GROUP=$RESOURCE_GROUP")" + + # Determine the directory of the script + SCRIPT_DIR="$(dirname "$0")" + + echo -e "\nSaving environment variables for reference...\n" + cat < $SCRIPT_DIR/env_vars.txt +export CLUSTER_NAME=$CLUSTER_NAME +export RESOURCE_GROUP=$RESOURCE_GROUP +EOL + + echo -e "A file named $(print_green "env_vars.txt") has been created with environment variables above..." + echo -e "\nTo set the environment variables, run:" + echo -e "\033[32msource $SCRIPT_DIR/env_vars.txt\033[0m" + +fi \ No newline at end of file diff --git a/tools/example/cmd/main.go b/tools/example/cmd/main.go deleted file mode 100644 index 99d1b49..0000000 --- a/tools/example/cmd/main.go +++ /dev/null @@ -1,10 +0,0 @@ -package main - -import ( - "github.com/Azure-Samples/aio-dev-toolbox/toolbox/tools/example/pkg/example" -) - -func main() { - example := &example.Example{} - example.Print() -} diff --git a/tools/example/pkg/example/example.go b/tools/example/pkg/example/example.go deleted file mode 100644 index b81f9a3..0000000 --- a/tools/example/pkg/example/example.go +++ /dev/null @@ -1,11 +0,0 @@ -package example - -import "fmt" - -// Example shows that all exported symbols must have a comment like this. -type Example struct {} - -// Print shows that the exported symbol comments applies to functions as well. -func (*Example) Print() { - fmt.Println("Example package") -} \ No newline at end of file diff --git a/tools/example/pkg/example/example_test.go b/tools/example/pkg/example/example_test.go deleted file mode 100644 index e62fd50..0000000 --- a/tools/example/pkg/example/example_test.go +++ /dev/null @@ -1,8 +0,0 @@ -package example - -import "testing" - -// Every package must have a test file and must meet a minimum test coverage to be merged into the toolbox. -func TestMain(m *testing.M) { - m.Run() -} From 3ade204533943760b430729d45be430f9e51b02b Mon Sep 17 00:00:00 2001 From: Ethan Date: Thu, 9 Nov 2023 11:53:45 -0800 Subject: [PATCH 4/4] Add code owners for PR reviews --- .github/CODEOWNERS | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..b5f6949 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,4 @@ +ethanperry1 +jlian +ryanwinter +udtri \ No newline at end of file