Skip to content

Commit

Permalink
Start to add eventing dashboards.
Browse files Browse the repository at this point in the history
This creates sections for "topics" and "subscriptions" that filter on their respective prefixes.

The topic section shows both topic metrics and subscription metrics for topics matching the prefix.
The subscription section shows the subscription metrics for subscriptions matching the prefix.

Building on this, the broker ingress now has a customized dashboard that takes advantage of the topic metrics to put them front-and-center.
Also building on this, the event recorder now includes a section with subscription metrics for each even type.

Signed-off-by: Matt Moore <[email protected]>
  • Loading branch information
mattmoor committed Dec 20, 2023
1 parent 763b08d commit 21cb6fe
Show file tree
Hide file tree
Showing 11 changed files with 467 additions and 8 deletions.
1 change: 1 addition & 0 deletions .github/workflows/documentation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ jobs:
- networking
- dashboard/service
- dashboard/job
- dashboard/cloudevent-receiver

steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
Expand Down
8 changes: 7 additions & 1 deletion cloudevent-broker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,20 @@ No requirements.

| Name | Source | Version |
|------|--------|---------|
| <a name="module_ingress-dashboard"></a> [ingress-dashboard](#module\_ingress-dashboard) | ../dashboard/service | n/a |
| <a name="module_http"></a> [http](#module\_http) | ../dashboard/sections/http | n/a |
| <a name="module_layout"></a> [layout](#module\_layout) | ../dashboard/sections/layout | n/a |
| <a name="module_logs"></a> [logs](#module\_logs) | ../dashboard/sections/logs | n/a |
| <a name="module_resources"></a> [resources](#module\_resources) | ../dashboard/sections/resources | n/a |
| <a name="module_topic"></a> [topic](#module\_topic) | ../dashboard/sections/topic | n/a |
| <a name="module_width"></a> [width](#module\_width) | ../dashboard/sections/width | n/a |

## Resources

| Name | Type |
|------|------|
| [cosign_sign.this](https://registry.terraform.io/providers/chainguard-dev/cosign/latest/docs/resources/sign) | resource |
| [google_cloud_run_v2_service.this](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloud_run_v2_service) | resource |
| [google_monitoring_dashboard.dashboard](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/monitoring_dashboard) | resource |
| [google_pubsub_topic.this](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/pubsub_topic) | resource |
| [google_pubsub_topic_iam_binding.ingress-publishes-events](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/pubsub_topic_iam_binding) | resource |
| [google_service_account.this](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account) | resource |
Expand Down
54 changes: 51 additions & 3 deletions cloudevent-broker/ingress.tf
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,55 @@ resource "google_cloud_run_v2_service" "this" {
}
}

module "ingress-dashboard" {
source = "../dashboard/service"
service_name = var.name
module "topic" {
source = "../dashboard/sections/topic"
title = "Broker Events"
topic_prefix = var.name
}

module "logs" {
source = "../dashboard/sections/logs"
title = "Service Logs"
filter = ["resource.type=\"cloud_run_revision\""]
}

module "http" {
source = "../dashboard/sections/http"
title = "HTTP"
filter = ["resource.type=\"cloud_run_revision\""]
}

module "resources" {
source = "../dashboard/sections/resources"
title = "Resources"
filter = ["resource.type=\"cloud_run_revision\""]
}

module "width" { source = "../dashboard/sections/width" }

module "layout" {
source = "../dashboard/sections/layout"
sections = [
module.topic.section,
module.logs.section,
module.http.section,
module.resources.section,
]
}

resource "google_monitoring_dashboard" "dashboard" {
dashboard_json = jsonencode({
displayName = "Cloud Events Broker Ingress: ${var.name}"
dashboardFilters = [{
filterType = "RESOURCE_LABEL"
stringValue = var.name
labelKey = "service_name"
}]

// https://cloud.google.com/monitoring/api/ref_v3/rest/v1/projects.dashboards#mosaiclayout
mosaicLayout = {
columns = module.width.size
tiles = module.layout.tiles,
}
})
}
2 changes: 1 addition & 1 deletion cloudevent-recorder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ No requirements.

| Name | Source | Version |
|------|--------|---------|
| <a name="module_recorder-dashboard"></a> [recorder-dashboard](#module\_recorder-dashboard) | ../dashboard/service | n/a |
| <a name="module_recorder-dashboard"></a> [recorder-dashboard](#module\_recorder-dashboard) | ../dashboard/cloudevent-receiver | n/a |
| <a name="module_triggers"></a> [triggers](#module\_triggers) | ../cloudevent-trigger | n/a |

## Resources
Expand Down
10 changes: 7 additions & 3 deletions cloudevent-recorder/recorder.tf
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ resource "google_cloud_run_v2_service" "recorder-service" {
}

resource "random_id" "trigger-suffix" {
for_each = local.regional-types
for_each = var.types
byte_length = 2
}

Expand All @@ -109,7 +109,7 @@ module "triggers" {

source = "../cloudevent-trigger"

name = "${var.name}-${random_id.trigger-suffix[each.key].hex}"
name = "${var.name}-${random_id.trigger-suffix[each.value.type].hex}"
project_id = var.project_id
broker = var.broker[each.value.region]
filter = { "type" : each.value.type }
Expand All @@ -122,6 +122,10 @@ module "triggers" {
}

module "recorder-dashboard" {
source = "../dashboard/service"
source = "../dashboard/cloudevent-receiver"
service_name = var.name

triggers = {
for type in var.types : "type: ${each.key}" => "${var.name}-${random_id.trigger-suffix[each.value.type].hex}"
}
}
1 change: 1 addition & 0 deletions dashboard/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
The modules in this directory define [`google_monitoring_dashboard`](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/monitoring_dashboard) resources in a repeatable structured way.

- The [Service](service/README.md) and [Job](job/README.md) modules define pre-configured dashboards for Cloud Run services and Cloud Run jobs, respectively.
- The [`cloudevent-receiver`](cloudevent-receiver/README.md) module defines a pre-configured dashboard for a Cloud Run-based event handler receiving events from a `cloudevent-trigger`.
- The modules in [`./widgets`](widgets/) define the widgets used by the dashboards, in a way that can be reused to create custom dashboards.
99 changes: 99 additions & 0 deletions dashboard/cloudevent-receiver/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# `dashboard/cloudevent-receiver`

This module provisions a Google Cloud Monitoring dashboard for a regionalized Cloud Run service that receives Cloud Events from one or more `cloudevent-trigger`.

It assumes the service has the same name in all regions.

```hcl
// Create a network with several regional subnets
module "networking" {
source = "chainguard-dev/glue/cloudrun//networking"
name = "my-networking"
project_id = var.project_id
regions = [...]
}
// Run a regionalized cloud run service "receiver" to handle events.
resource "google_cloud_run_v2_service" "receiver" {
for_each = module.networking.regional-networks
name = "receiver"
//...
template {
//...
containers {
image = "..."
}
}
}
module "cloudevent-trigger" {
for_each = module.networking.regional-networks
source = "chainguard-dev/glue/cloudrun//cloudevent-trigger"
name = "my-trigger"
project_id = var.project_id
broker = module.cloudevent-broker.broker[each.key]
filter = { "type" : "dev.chainguard.foo" }
depends_on = [google_cloud_run_v2_service.sockeye]
private-service = {
region = each.key
name = google_cloud_run_v2_service.receiver[each.key].name
}
}
// Set up a dashboard for a regionalized event handler named "receiver".
module "receiver-dashboard" {
source = "chainguard-dev/glue/cloudrun//dashboard/cloudevent-receiver"
service_name = "receiver"
triggers = {
"type dev.chainguard.foo": "my-trigger"
}
}
```

The dashboard it creates includes widgets for service logs, request count, latency (p50,p95,p99), instance count grouped by revision, CPU and memory utilization, startup latency, and sent/received bytes.

<!-- BEGIN_TF_DOCS -->
## Requirements

No requirements.

## Providers

| Name | Version |
|------|---------|
| <a name="provider_google"></a> [google](#provider\_google) | n/a |

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_http"></a> [http](#module\_http) | ../sections/http | n/a |
| <a name="module_layout"></a> [layout](#module\_layout) | ../sections/layout | n/a |
| <a name="module_logs"></a> [logs](#module\_logs) | ../sections/logs | n/a |
| <a name="module_resources"></a> [resources](#module\_resources) | ../sections/resources | n/a |
| <a name="module_subscription"></a> [subscription](#module\_subscription) | ../sections/subscription | n/a |
| <a name="module_width"></a> [width](#module\_width) | ../sections/width | n/a |

## Resources

| Name | Type |
|------|------|
| [google_monitoring_dashboard.dashboard](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/monitoring_dashboard) | resource |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_service_name"></a> [service\_name](#input\_service\_name) | Name of the service(s) to monitor | `string` | n/a | yes |
| <a name="input_triggers"></a> [triggers](#input\_triggers) | A mapping from a descriptive name to a subscription name prefix. | `map(string)` | n/a | yes |

## Outputs

No outputs.
<!-- END_TF_DOCS -->
57 changes: 57 additions & 0 deletions dashboard/cloudevent-receiver/dashboard.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
module "subscription" {
for_each = var.triggers

source = "../sections/subscription"
title = "Events ${each.key}"

subscription_prefix = each.value
}

module "logs" {
source = "../sections/logs"
title = "Service Logs"
filter = ["resource.type=\"cloud_run_revision\""]
}

module "http" {
source = "../sections/http"
title = "HTTP"
filter = ["resource.type=\"cloud_run_revision\""]
}

module "resources" {
source = "../sections/resources"
title = "Resources"
filter = ["resource.type=\"cloud_run_revision\""]
}

module "width" { source = "../sections/width" }

module "layout" {
source = "../sections/layout"
sections = concat([
for key in sort(keys(var.triggers)) : module.subscription[key].section
],
[
module.logs.section,
module.http.section,
module.resources.section,
])
}

resource "google_monitoring_dashboard" "dashboard" {
dashboard_json = jsonencode({
displayName = "Cloud Event Receiver: ${var.service_name}"
dashboardFilters = [{
filterType = "RESOURCE_LABEL"
stringValue = var.service_name
labelKey = "service_name"
}]

// https://cloud.google.com/monitoring/api/ref_v3/rest/v1/projects.dashboards#mosaiclayout
mosaicLayout = {
columns = module.width.size
tiles = module.layout.tiles,
}
})
}
9 changes: 9 additions & 0 deletions dashboard/cloudevent-receiver/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
variable "service_name" {
description = "Name of the service(s) to monitor"
type = string
}

variable "triggers" {
description = "A mapping from a descriptive name to a subscription name prefix."
type = map(string)
}
88 changes: 88 additions & 0 deletions dashboard/sections/subscription/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
variable "title" { type = string }
variable "subscription_prefix" { type = string }
variable "collapsed" { default = false }

module "width" { source = "../width" }

module "received-events" {
source = "../../widgets/xy"
title = "Events Pushed"
filter = [
"resource.type=\"pubsub_subscription\"",
"metric.type=\"pubsub.googleapis.com/subscription/push_request_count\"",
"resource.label.\"subscription_id\"=monitoring.regex.full_match(\"${var.subscription_prefix}-.*\")",
]
group_by_fields = [
"resource.label.\"subscription_id\"",
"metric.label.\"response_class\""
]
primary_align = "ALIGN_MEAN"
primary_reduce = "REDUCE_NONE"
}

module "push-latency" {
source = "../../widgets/latency"
title = "Push latency"
filter = [
"resource.type=\"pubsub_subscription\"",
"metric.type=\"pubsub.googleapis.com/subscription/push_request_latencies\"",
"resource.label.\"subscription_id\"=monitoring.regex.full_match(\"${var.subscription_prefix}-.*\")",
]
group_by_fields = ["resource.label.\"subscription_id\""]
}

module "oldest-unacked" {
source = "../../widgets/xy"
title = "Oldest unacked message age"
filter = [
"resource.type=\"pubsub_subscription\"",
"metric.type=\"pubsub.googleapis.com/subscription/oldest_unacked_message_age\"",
"resource.label.\"subscription_id\"=monitoring.regex.full_match(\"${var.subscription_prefix}-.*\")",
]
group_by_fields = ["resource.label.\"subscription_id\""]
primary_align = "ALIGN_MAX"
primary_reduce = "REDUCE_NONE"
}

locals {
columns = 3
unit = module.width.size / local.columns

// https://www.terraform.io/language/functions/range
// N columns, unit width each ([0, unit, 2 * unit, ...])
col = range(0, local.columns * local.unit, local.unit)

tiles = [{
yPos = 0,
xPos = local.col[0],
height = local.unit,
width = local.unit,
widget = module.received-events.widget,
},
{
yPos = 0,
xPos = local.col[1],
height = local.unit,
width = local.unit,
widget = module.push-latency.widget,
},
{
yPos = 0,
xPos = local.col[2],
height = local.unit,
width = local.unit,
widget = module.oldest-unacked.widget,
}]
}

module "collapsible" {
source = "../collapsible"

title = var.title
tiles = local.tiles
collapsed = var.collapsed
}

output "section" {
value = module.collapsible.section
}
Loading

0 comments on commit 21cb6fe

Please sign in to comment.