cpflow 5.1.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/.agents/agent-workflow.yml +15 -0
  3. data/.agents/bin/README.md +19 -0
  4. data/.agents/bin/docs +5 -0
  5. data/.agents/bin/lint +5 -0
  6. data/.agents/bin/setup +5 -0
  7. data/.agents/bin/test +5 -0
  8. data/.agents/bin/validate +5 -0
  9. data/.agents/trusted-github-actors.yml +32 -0
  10. data/.agents/workflows/ai-rollout-e2e-test.md +166 -0
  11. data/.github/actions/cpflow-wait-for-health/action.yml +11 -4
  12. data/.github/workflows/claude-code-review.yml +2 -0
  13. data/.github/workflows/claude.yml +2 -0
  14. data/.github/workflows/cpflow-deploy-review-app.yml +16 -1
  15. data/.github/workflows/cpflow-promote-staging-to-production.yml +224 -37
  16. data/.github/workflows/rspec-shared.yml +15 -1
  17. data/.github/workflows/rspec-specific.yml +1 -0
  18. data/.github/workflows/rspec.yml +58 -1
  19. data/AGENTS.md +57 -0
  20. data/CHANGELOG.md +36 -1
  21. data/CLAUDE.md +3 -0
  22. data/CONTRIBUTING.md +6 -2
  23. data/Gemfile.lock +1 -1
  24. data/README.md +25 -7
  25. data/docs/ai-github-flow-prompt.md +18 -16
  26. data/docs/assets/logo/favicon.ico +0 -0
  27. data/docs/assets/logo/icon-1024.png +0 -0
  28. data/docs/assets/logo/icon-128.png +0 -0
  29. data/docs/assets/logo/icon-16.png +0 -0
  30. data/docs/assets/logo/icon-192.png +0 -0
  31. data/docs/assets/logo/icon-24.png +0 -0
  32. data/docs/assets/logo/icon-32.png +0 -0
  33. data/docs/assets/logo/icon-48.png +0 -0
  34. data/docs/assets/logo/icon-512.png +0 -0
  35. data/docs/assets/logo/icon-64.png +0 -0
  36. data/docs/assets/logo/icon-tile.svg +17 -0
  37. data/docs/assets/logo/mark-transparent.svg +16 -0
  38. data/docs/ci-automation.md +203 -15
  39. data/docs/commands.md +16 -1
  40. data/docs/grafana-opentelemetry.md +699 -0
  41. data/docs/secrets-and-env-values.md +29 -2
  42. data/docs/sidebars.ts +70 -0
  43. data/docs/telemetry/application-instrumentation.md +161 -0
  44. data/docs/telemetry/collector.md +297 -0
  45. data/docs/telemetry/index.md +152 -0
  46. data/docs/telemetry/pipelines.md +98 -0
  47. data/docs/telemetry/review-apps.md +55 -0
  48. data/docs/telemetry/troubleshooting.md +92 -0
  49. data/docs/terraform/example/.controlplane/controlplane.yml +0 -1
  50. data/docs/terraform/overview.md +11 -0
  51. data/docs/tips.md +458 -29
  52. data/examples/controlplane.yml +2 -0
  53. data/lib/command/ai_github_flow_prompt.rb +2 -2
  54. data/lib/command/base.rb +17 -2
  55. data/lib/command/deploy_image.rb +77 -5
  56. data/lib/command/maintenance_off.rb +1 -0
  57. data/lib/command/maintenance_on.rb +1 -0
  58. data/lib/command/promote_app_from_upstream.rb +1 -0
  59. data/lib/command/ps_wait.rb +2 -10
  60. data/lib/command/run.rb +25 -5
  61. data/lib/core/config.rb +94 -0
  62. data/lib/core/doctor_service.rb +44 -3
  63. data/lib/core/maintenance_mode.rb +93 -6
  64. data/lib/core/template_parser.rb +43 -9
  65. data/lib/cpflow/version.rb +1 -1
  66. data/lib/generator_templates/controlplane.yml +1 -2
  67. data/lib/github_flow_templates/.github/cpflow-help.md +23 -1
  68. data/lib/github_flow_templates/.github/workflows/cpflow-promote-staging-to-production.yml +224 -39
  69. metadata +33 -2
@@ -0,0 +1,152 @@
1
+ # Telemetry
2
+
3
+ This guide explains how to run application telemetry on Control Plane with
4
+ `cpflow`. It is intentionally generic: the examples use placeholder service
5
+ names, simple metric names, and backend-neutral collector configuration.
6
+
7
+ `cpflow` does not instrument application code. It helps deploy the Control Plane
8
+ workloads and environment values that already-instrumented applications use to
9
+ send traces, metrics, and logs.
10
+
11
+ ## Quick Navigation
12
+
13
+ | Page | Use it for |
14
+ | --- | --- |
15
+ | [Collector workload](collector.md) | Control Plane workload template, collector ports, and matching `config.yaml` |
16
+ | [Application instrumentation](application-instrumentation.md) | Generic app env vars and simple Ruby/Node examples |
17
+ | [Pipelines](pipelines.md) | Receivers, processors, exporters, and how signals flow |
18
+ | [Review apps](review-apps.md) | Review-app isolation, sampling, secrets, and egress controls |
19
+ | [Troubleshooting](troubleshooting.md) | Commands and checks for missing telemetry |
20
+
21
+ ## Recommended Shape
22
+
23
+ ```mermaid
24
+ flowchart LR
25
+ app["Application workload(s)"]
26
+ collector["Collector workload"]
27
+ backend["Telemetry backend(s)"]
28
+ dashboard["Dashboards and alerts"]
29
+
30
+ app -->|"OTLP HTTP :4318"| collector
31
+ app -->|"Optional StatsD TCP :9127"| collector
32
+ collector -->|"Traces, metrics, logs"| backend
33
+ backend --> dashboard
34
+ ```
35
+
36
+ Keep the collector inside the same GVC as the application unless your team has a
37
+ separate, intentionally shared telemetry GVC. A same-GVC collector keeps review,
38
+ staging, and production wiring easy to reason about and avoids accidental
39
+ cross-environment data mixing.
40
+
41
+ ## What `cpflow` Provides
42
+
43
+ `cpflow apply-template` already applies ordinary Control Plane workload
44
+ templates from `.controlplane/templates`. Telemetry can therefore be added with
45
+ project templates and app environment values; no custom `cpflow telemetry`
46
+ command is required.
47
+
48
+ Use `cpflow` for:
49
+
50
+ 1. Deploying an OpenTelemetry Collector workload template.
51
+ 2. Applying GVC or workload environment variables that point apps at the
52
+ collector.
53
+ 3. Reusing the same setup shape for review, staging, and production apps.
54
+ 4. Tailing application and collector logs with `cpflow logs`.
55
+
56
+ Application code is still responsible for:
57
+
58
+ 1. Installing OpenTelemetry, StatsD, Prometheus, or framework-specific
59
+ instrumentation libraries.
60
+ 2. Setting service names and resource attributes.
61
+ 3. Creating custom spans or metrics.
62
+ 4. Filtering sensitive data before it leaves the process.
63
+
64
+ ## Signal Flow
65
+
66
+ ```mermaid
67
+ flowchart TB
68
+ subgraph app["Application process"]
69
+ trace_sdk["Trace SDK"]
70
+ metric_sdk["Metric SDK"]
71
+ otlp_logs["OTLP logs"]
72
+ stdout_logs["stdout/stderr logs"]
73
+ end
74
+
75
+ subgraph collector["Collector workload"]
76
+ receivers["Receivers"]
77
+ processors["Processors"]
78
+ exporters["Exporters"]
79
+ end
80
+
81
+ traces["Trace backend"]
82
+ metrics["Metrics backend"]
83
+ logs["OTLP log backend"]
84
+ platform_logs["Platform log capture"]
85
+ platform_logs_backend["Platform log backend"]
86
+
87
+ trace_sdk -->|"OTLP traces"| receivers
88
+ metric_sdk -->|"OTLP metrics or StatsD TCP"| receivers
89
+ otlp_logs -->|"OTLP logs"| receivers
90
+ stdout_logs -->|"bypasses collector"| platform_logs
91
+ platform_logs -->|"cpflow logs and historical queries"| platform_logs_backend
92
+ receivers --> processors
93
+ processors --> exporters
94
+ exporters --> traces
95
+ exporters --> metrics
96
+ exporters --> logs
97
+ ```
98
+
99
+ stdout/stderr logs bypass the collector and are captured directly by the
100
+ platform. Use `cpflow logs` for live tailing.
101
+
102
+ For new instrumentation, prefer OTLP over HTTP on port `4318`. It is the most
103
+ portable path because it can carry traces, metrics, and logs through one
104
+ well-known protocol. Use StatsD only when your application already has a simple
105
+ StatsD client or when a metric library cannot emit OTLP yet.
106
+
107
+ ## Minimal Rollout Checklist
108
+
109
+ 1. Add `.controlplane/templates/open-telemetry-collector-secrets.yml` and
110
+ `.controlplane/templates/open-telemetry-collector.yml`.
111
+ 2. Package a collector `config.yaml` that binds every port exposed by the
112
+ workload template.
113
+ 3. Build the collector image and push it to your registry. Update the workload
114
+ template's `image:` field to that pushed image reference before applying it.
115
+ 4. Add both collector templates to `setup_app_templates` in
116
+ `.controlplane/controlplane.yml` (see
117
+ [Collector `controlplane.yml`](collector.md#controlplaneyml)):
118
+ `open-telemetry-collector-secrets` first, then
119
+ `open-telemetry-collector`.
120
+ 5. Add the collector to `additional_workloads` in
121
+ `.controlplane/controlplane.yml`.
122
+ 6. Set application env vars such as `OTEL_SERVICE_NAME`,
123
+ `OTEL_EXPORTER_OTLP_ENDPOINT`, and `OTEL_EXPORTER_OTLP_PROTOCOL`.
124
+ 7. For an existing app, apply both collector templates in the same order:
125
+ identity and policy first, then the collector workload.
126
+
127
+ ```sh
128
+ cpflow apply-template open-telemetry-collector-secrets -a $APP_NAME
129
+ cpflow apply-template open-telemetry-collector -a $APP_NAME
130
+ ```
131
+
132
+ For a brand-new app, `cpflow setup-app` applies the configured templates in
133
+ `setup_app_templates` order.
134
+ 8. Confirm collector logs, application exporter logs, and backend ingestion.
135
+
136
+ The collector workload and its `config.yaml` must be kept in sync. If the
137
+ workload exposes `4318`, `9127`, or `9292`, the collector config must bind those
138
+ same ports. Exposing a port in Control Plane does not automatically enable a
139
+ collector receiver or exporter.
140
+
141
+ ## Generic Naming
142
+
143
+ Use generic service names, metric names, and resource attributes in reusable
144
+ telemetry templates. See
145
+ [Service Names](application-instrumentation.md#service-names) for examples and
146
+ avoidance rules.
147
+
148
+ ## More Detail
149
+
150
+ Start with [Collector workload](collector.md), then read
151
+ [Application instrumentation](application-instrumentation.md). Use
152
+ [Troubleshooting](troubleshooting.md) when signals do not appear in the backend.
@@ -0,0 +1,98 @@
1
+ # Telemetry Pipelines
2
+
3
+ Collectors organize telemetry into signal-specific pipelines. Each pipeline has
4
+ receivers, optional processors, and exporters.
5
+
6
+ ```mermaid
7
+ flowchart LR
8
+ receiver["Receiver"]
9
+ processor["Processor"]
10
+ exporter["Exporter"]
11
+
12
+ receiver --> processor
13
+ processor --> exporter
14
+ ```
15
+
16
+ ## Pipeline Components
17
+
18
+ | Component | Role | Examples |
19
+ | --- | --- | --- |
20
+ | Receiver | Accepts telemetry from apps | OTLP HTTP, StatsD TCP |
21
+ | Processor | Modifies, batches, filters, or samples telemetry | `batch`, `memory_limiter`, `attributes` |
22
+ | Exporter | Sends telemetry to a backend or exposes it for scrape | OTLP exporter, Prometheus exporter, debug exporter |
23
+
24
+ ## Recommended Initial Pipelines
25
+
26
+ ```mermaid
27
+ flowchart TB
28
+ app["Application"]
29
+ otlp["OTLP receiver :4318"]
30
+ statsd["Optional StatsD TCP metrics receiver :9127"]
31
+ traces_processors["Trace processors"]
32
+ metrics_processors["Metrics processors"]
33
+ logs_processors["Log processors"]
34
+ traces["Trace exporter"]
35
+ metrics_push["Metrics push exporter"]
36
+ prometheus["Prometheus scrape exporter :9292"]
37
+ logs["Log exporter"]
38
+
39
+ app -->|"OTLP traces, metrics, logs"| otlp
40
+ app -->|"StatsD metrics only"| statsd
41
+ otlp -->|"traces"| traces_processors --> traces
42
+ otlp -->|"metrics"| metrics_processors
43
+ statsd -->|"metrics"| metrics_processors
44
+ metrics_processors --> metrics_push
45
+ metrics_processors --> prometheus
46
+ otlp -->|"logs"| logs_processors --> logs
47
+ ```
48
+
49
+ Start with direct application telemetry:
50
+
51
+ 1. OTLP traces from the app SDK.
52
+ 2. OTLP metrics from the app SDK, or StatsD TCP if that is what the app already
53
+ supports.
54
+ 3. Structured logs to stdout/stderr, or OTLP logs if your logging library
55
+ supports them.
56
+
57
+ ## Direct Metrics First
58
+
59
+ Prefer direct metrics from application code when you can change the code. Direct
60
+ metrics are explicit, cheap, and easy to test.
61
+
62
+ Good direct metrics:
63
+
64
+ - `example.requests.completed`
65
+ - `example.jobs.duration_ms`
66
+ - `example.queue.depth`
67
+ - `example.cache.hit`
68
+
69
+ Use low-cardinality labels such as:
70
+
71
+ - `status`
72
+ - `route_name`
73
+ - `worker`
74
+ - `deployment.environment`
75
+
76
+ ## Derived Metrics
77
+
78
+ Derived metrics can be useful, but they should not be the default for new work.
79
+
80
+ | Source | Use when | Caution |
81
+ | --- | --- | --- |
82
+ | Spans | You already have spans and need latency/error histograms | Attribute choices can create high cardinality |
83
+ | Logs | You cannot change legacy code yet | Regex processing is expensive and fragile |
84
+
85
+ When a derived metric proves valuable, prefer moving it into direct application
86
+ instrumentation later.
87
+
88
+ ## Sampling
89
+
90
+ Sampling belongs in the collector when you need centralized control. A common
91
+ policy shape is:
92
+
93
+ 1. Keep all error traces.
94
+ 2. Keep a small percentage of fast successful traces.
95
+ 3. Keep a larger percentage of slow successful traces.
96
+
97
+ Record sampling decisions in the collector config so agents and humans know why
98
+ some traces are absent.
@@ -0,0 +1,55 @@
1
+ # Review Apps
2
+
3
+ Review-app telemetry should help debug a change without giving untrusted or
4
+ short-lived environments access to production telemetry credentials.
5
+
6
+ ```mermaid
7
+ flowchart TB
8
+ subgraph review["Review app GVC"]
9
+ app["Review app workloads"]
10
+ collector["Review collector"]
11
+ end
12
+
13
+ subgraph staging["Staging telemetry"]
14
+ backend["Non-production backend"]
15
+ end
16
+
17
+ app --> collector
18
+ collector --> backend
19
+ ```
20
+
21
+ ## Recommended Defaults
22
+
23
+ 1. Use a collector inside each review app GVC, or a staging-only shared collector
24
+ that is intentionally isolated from production.
25
+ 2. Keep collector inbound access internal with `same-gvc` when the collector is
26
+ inside the review app GVC. For a staging-only shared collector in another
27
+ GVC, configure explicit cross-GVC ingress instead of broad public access.
28
+ 3. Do not give review apps production telemetry tokens.
29
+ 4. Use lower sampling rates and shorter retention for review apps.
30
+ 5. Avoid sending request bodies, credentials, or personally identifiable
31
+ information in spans, labels, or logs.
32
+ 6. Restrict outbound egress to the non-production telemetry backend.
33
+
34
+ ## Environment Separation
35
+
36
+ Use resource attributes to make review telemetry easy to filter:
37
+
38
+ ```yaml
39
+ env:
40
+ - name: OTEL_RESOURCE_ATTRIBUTES
41
+ value: "deployment.environment=review,service.namespace=example"
42
+ ```
43
+
44
+ If every review app has a unique name, keep that name in a bounded attribute only
45
+ when your backend can handle the cardinality. Do not put pull request titles,
46
+ branch names, user names, or request IDs into metric labels.
47
+
48
+ ## Secrets
49
+
50
+ Store backend tokens in Control Plane secrets and bind only the collector
51
+ identity that needs them. See [Secrets and ENV Values](../secrets-and-env-values.md)
52
+ for the general Control Plane secret pattern.
53
+
54
+ Review apps should use non-production tokens. If no non-production token exists,
55
+ keep telemetry local to logs until one is available.
@@ -0,0 +1,92 @@
1
+ # Telemetry Troubleshooting
2
+
3
+ Use this checklist when telemetry does not appear in the backend.
4
+
5
+ Set `APP_NAME` before running the examples:
6
+
7
+ ```sh
8
+ APP_NAME=your-app-name
9
+ ```
10
+
11
+ ## 1. Confirm Workloads
12
+
13
+ ```sh
14
+ cpflow ps -a $APP_NAME -w open-telemetry-collector
15
+ cpflow ps -a $APP_NAME -w app
16
+ ```
17
+
18
+ Replace `app` with the workload you are checking.
19
+
20
+ `cpflow ps` lists running replicas. If the collector is deployed but scaled to
21
+ zero, restart or scale it before debugging collector config or application
22
+ exporter settings.
23
+
24
+ ## 2. Check Collector Logs
25
+
26
+ ```sh
27
+ cpflow logs -a $APP_NAME -w open-telemetry-collector
28
+ ```
29
+
30
+ Look for:
31
+
32
+ - config parse errors
33
+ - receiver bind failures
34
+ - exporter authentication failures
35
+ - backend DNS or connection failures
36
+ - dropped data due to memory or queue limits
37
+
38
+ ## 3. Check Application Logs
39
+
40
+ ```sh
41
+ cpflow logs -a $APP_NAME -w app
42
+ ```
43
+
44
+ Look for exporter errors from the application SDK. Common causes are:
45
+
46
+ - wrong `OTEL_EXPORTER_OTLP_ENDPOINT`
47
+ - app instrumentation not enabled
48
+ - collector service name typo
49
+ - unsupported protocol value
50
+ - backend token missing from the collector
51
+
52
+ ## 4. Verify Port Agreement
53
+
54
+ The Control Plane workload template and collector config must agree.
55
+
56
+ | Symptom | Check |
57
+ | --- | --- |
58
+ | App cannot export OTLP | Workload exposes `4318`; collector binds `0.0.0.0:4318` |
59
+ | StatsD metrics missing | Workload exposes `9127`; collector has `statsd/tcp` on `0.0.0.0:9127` |
60
+ | Prometheus scrape empty | Workload exposes `9292`; collector has `prometheus` exporter on `0.0.0.0:9292` |
61
+
62
+ ## 5. Verify DNS
63
+
64
+ From an app workload shell, check that the collector service name resolves:
65
+
66
+ ```sh
67
+ getent hosts open-telemetry-collector.${APP_NAME}.cpln.local
68
+ ```
69
+
70
+ Set `APP_NAME` to the actual app name. If your image does not include `getent`,
71
+ use an equivalent DNS tool available in the image.
72
+
73
+ ## 6. Keep The First Test Simple
74
+
75
+ Before adding sampling, filtering, derived metrics, or multiple exporters:
76
+
77
+ 1. Start with one app workload.
78
+ 2. Send OTLP traces over HTTP.
79
+ 3. Export to a debug exporter or one known backend. To enable the debug
80
+ exporter, uncomment the `debug:` block in your collector config, add `debug`
81
+ to the relevant pipeline exporters list, and rebuild or remount the config.
82
+ Remove the debug exporter before production use; it writes full telemetry
83
+ payloads to collector logs.
84
+ 4. Confirm data appears.
85
+ 5. Add metrics and logs after traces work.
86
+
87
+ Use the debug exporter only for short validation windows. It writes full
88
+ telemetry payloads to collector logs, so remove or disable it before sending
89
+ production traffic or attributes that may contain sensitive data.
90
+
91
+ Small steps make it much easier to tell whether the app, collector, network, or
92
+ backend is the source of the problem.
@@ -19,7 +19,6 @@ apps:
19
19
  <<: *common
20
20
  hooks:
21
21
  post_creation: bundle exec rake db:prepare
22
- pre_deletion: bundle exec rake db:drop
23
22
 
24
23
  rails-app-production:
25
24
  <<: *common
@@ -15,6 +15,17 @@ You can continue working with CPLN configuration files in YAML format and start
15
15
  3. **Multi-Cloud Support**: With Terraform, you can manage resources across multiple cloud providers seamlessly, allowing for a more flexible architecture.
16
16
  4. **Plan and Apply**: Terraform provides a clear plan of what changes will be made before applying them, reducing the risk of unintended modifications.
17
17
 
18
+ ## Terraform and `cpflow` Are Complementary
19
+
20
+ Generating Terraform does not replace `cpflow`. The two cover different parts of the workflow, and most teams use both:
21
+
22
+ - **`cpflow` YAML + `cpflow deploy-image`** fits **ephemeral, fast-moving environments** — Heroku-style review apps in particular. Dynamic per-PR app names, [`cleanup-stale-apps`](/docs/tips.md#delete-or-pause-abandoned-apps-with-cleanup-stale-apps), [`ps:stop`/`ps:start`](/docs/tips.md#pause-and-resume-with-psstop--psstart), and the build → release → deploy flow are first-class, and there is no Terraform state to manage for apps that come and go.
23
+ - **Generated Terraform + `terraform apply`** fits **long-lived, stable environments** (staging and production) where you want a tracked state file, drift detection, explicit dependency ordering, and integration with other Terraform-managed infrastructure.
24
+
25
+ Because `cpflow terraform generate` produces the Terraform from the same `.controlplane/templates/`, adopting Terraform for your stable environments does not mean maintaining two separate configurations — the YAML templates remain the source of truth, and you regenerate when they change.
26
+
27
+ A practical split: keep review apps on the `cpflow deploy-image` flow, and manage staging and production with the generated Terraform. `terraform plan` then surfaces drift for Terraform-managed resources before you apply — see [Tips → Keep Templates as the Source of Truth](/docs/tips.md#keep-templates-as-the-source-of-truth).
28
+
18
29
  ## Usage
19
30
 
20
31
  Let's take a look at how to deploy a [simple Rails application](https://github.com/shakacode/control-plane-flow/tree/main/docs/terraform/example/.controlplane/controlplane.yml) on CPLN using Terraform: