fly_io 0.1.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 (47) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +15 -0
  3. data/CONTRIBUTING.md +14 -0
  4. data/LICENSE +21 -0
  5. data/README.md +239 -0
  6. data/Rakefile +30 -0
  7. data/contracts/additional_rest/network_policies.json +94 -0
  8. data/contracts/additional_rest/prometheus.json +103 -0
  9. data/contracts/graphql/fly_go_operations.json +948 -0
  10. data/contracts/graphql/flyctl_named_operations.graphql +316 -0
  11. data/contracts/graphql/flyctl_operations.json +336 -0
  12. data/contracts/graphql/official_examples.json +75 -0
  13. data/contracts/graphql/schema.graphql +10995 -0
  14. data/contracts/graphql/source.json +29 -0
  15. data/contracts/machines/openapi.headers +9 -0
  16. data/contracts/machines/openapi.json +1 -0
  17. data/contracts/machines/source.json +20 -0
  18. data/contracts/public_surface_inventory.json +164 -0
  19. data/contracts/research_metadata.json +17 -0
  20. data/contracts/sources/metrics.html.md +474 -0
  21. data/contracts/sources/network-policies.html.markerb +142 -0
  22. data/docs/API.md +149 -0
  23. data/docs/SURFACES.md +60 -0
  24. data/lib/fly_io/client.rb +52 -0
  25. data/lib/fly_io/configuration.rb +115 -0
  26. data/lib/fly_io/errors.rb +45 -0
  27. data/lib/fly_io/generated/additional_operations.json +123 -0
  28. data/lib/fly_io/generated/graphql_operations.json +1658 -0
  29. data/lib/fly_io/generated/operations.json +6130 -0
  30. data/lib/fly_io/generated/prometheus_operations.json +503 -0
  31. data/lib/fly_io/generated/schemas.json +4237 -0
  32. data/lib/fly_io/graphql_client.rb +103 -0
  33. data/lib/fly_io/model.rb +65 -0
  34. data/lib/fly_io/operation_registry.rb +79 -0
  35. data/lib/fly_io/redactor.rb +34 -0
  36. data/lib/fly_io/resources/base.rb +68 -0
  37. data/lib/fly_io/resources.rb +30 -0
  38. data/lib/fly_io/response.rb +45 -0
  39. data/lib/fly_io/schema_registry.rb +89 -0
  40. data/lib/fly_io/schema_validator.rb +56 -0
  41. data/lib/fly_io/transport.rb +282 -0
  42. data/lib/fly_io/version.rb +5 -0
  43. data/lib/fly_io.rb +23 -0
  44. data/script/check_api_coverage +60 -0
  45. data/script/fetch_openapi +18 -0
  46. data/script/generate_api +302 -0
  47. metadata +197 -0
@@ -0,0 +1,20 @@
1
+ {
2
+ "surface": "machines_rest",
3
+ "stability": "stable",
4
+ "base_url": "https://api.machines.dev",
5
+ "contract_url": "https://docs.machines.dev/openapi.json",
6
+ "retrieved_at": "2026-08-26T20:30:19Z",
7
+ "etag": "\"222e4-Y2JlbkeX2XlDU7gTxh4WI2j04MM\"",
8
+ "last_modified": "Thu, 20 Aug 2026 16:50:52 GMT",
9
+ "sha256": "9e6a180c40a38bf20b72a8577a8cd93866f47882627b608af753cc4c22f7758f",
10
+ "openapi": "3.0.1",
11
+ "api_version": "1.0",
12
+ "paths": 68,
13
+ "operations": 98,
14
+ "unique_operation_ids": 97,
15
+ "schemas": 173,
16
+ "notes": [
17
+ "Machines_update_metadata is shared by PUT and PATCH on the metadata collection.",
18
+ "The contract declares no security scheme; official Fly docs define Bearer authentication."
19
+ ]
20
+ }
@@ -0,0 +1,164 @@
1
+ {
2
+ "retrieved_at": "2026-08-26",
3
+ "source_revisions": {
4
+ "flyctl": "1f906765dee8e973f6d1dd8fff65b58212e7b425",
5
+ "fly_go_v0_9_8": "858ec691152ab3faa0b0a0438726bda8144d8734",
6
+ "fly_docs": "1e8cac5f0fd7a82e66e3b01ece3a10a8ecb2b7e3"
7
+ },
8
+ "surfaces": [
9
+ {
10
+ "id": "machines_rest_openapi",
11
+ "classification": "public_documented_control_plane",
12
+ "stability": "official_versioned_reference_without_an_explicit_compatibility_policy",
13
+ "base_urls": {
14
+ "public": "https://api.machines.dev",
15
+ "private_wireguard": "http://_api.internal:4280"
16
+ },
17
+ "authentication": {
18
+ "official_guide": "Authorization: Bearer <fly_api_token>",
19
+ "generated_reference_text": "FlyV1 wording with a Bearer example",
20
+ "flyctl_behavior": "FlyV1 for macaroon tokens; Bearer for OAuth/user tokens",
21
+ "implementation_note": "Accept raw tokens and explicit preformatted authorization values; never duplicate a scheme"
22
+ },
23
+ "authoritative_contract": {
24
+ "url": "https://docs.machines.dev/openapi.json",
25
+ "openapi": "3.0.1",
26
+ "info_version": "1.0",
27
+ "sha256": "9e6a180c40a38bf20b72a8577a8cd93866f47882627b608af753cc4c22f7758f",
28
+ "bytes": 140004,
29
+ "etag": "\"222e4-Y2JlbkeX2XlDU7gTxh4WI2j04MM\"",
30
+ "last_modified": "Thu, 20 Aug 2026 16:50:52 GMT"
31
+ },
32
+ "counts": {
33
+ "paths": 68,
34
+ "operations": 98,
35
+ "unique_operation_ids": 97,
36
+ "schemas": 173,
37
+ "ref_occurrences": 315,
38
+ "unique_refs": 173,
39
+ "unresolved_refs": 0,
40
+ "methods": {"GET": 33, "POST": 43, "PUT": 4, "PATCH": 2, "DELETE": 16},
41
+ "families": {
42
+ "Apps": 8,
43
+ "TLS Certificates": 8,
44
+ "Machines": 29,
45
+ "Secrets": 14,
46
+ "Volumes": 8,
47
+ "Organizations": 2,
48
+ "Platform": 2,
49
+ "Postgres Clusters": 22,
50
+ "Tokens": 5
51
+ }
52
+ },
53
+ "contract_ambiguities": [
54
+ "Machines_update_metadata is duplicated for PUT and PATCH, so method plus path must be part of the operation key",
55
+ "The OpenAPI document defines neither securitySchemes nor top-level security",
56
+ "The generated landing page omits Organizations and Platform resource cards even though the operations exist",
57
+ "The top-level tags array omits several tags used by operations",
58
+ "Official Network Policies operations are absent from this contract"
59
+ ],
60
+ "official_sources": [
61
+ "https://fly.io/docs/machines/api/",
62
+ "https://docs.machines.dev/",
63
+ "https://fly.io/docs/machines/api/working-with-machines-api",
64
+ "https://fly.io/docs/machines/guides-examples/managing-machines-with-the-api"
65
+ ]
66
+ },
67
+ {
68
+ "id": "machines_network_policies",
69
+ "classification": "public_documented_control_plane_without_machine_readable_contract",
70
+ "stability": "no_explicit_stability_label",
71
+ "base_url": "https://api.machines.dev",
72
+ "authentication": "Authorization: Bearer <FLY_API_TOKEN>",
73
+ "authoritative_contract": null,
74
+ "prose_source": "https://fly.io/docs/machines/guides-examples/network-policies",
75
+ "operation_count": 3,
76
+ "operation_inventory": "network_policies_operations.json",
77
+ "openapi_status": "absent"
78
+ },
79
+ {
80
+ "id": "control_plane_graphql",
81
+ "classification": "public_endpoint_internal_unstable_control_plane",
82
+ "stability": "explicitly_no_stability_guarantees_and_may_change_without_notice",
83
+ "endpoint": "https://api.fly.io/graphql",
84
+ "authentication": "FlyV1 or Bearer as selected by token type in flyctl; official curl examples show Bearer",
85
+ "authoritative_contract": null,
86
+ "implementation_evidence": {
87
+ "flyctl_schema_path": "gql/schema.graphql",
88
+ "flyctl_schema_sha256": "2f1a1d0f2f8940277e5e14002c78cb4f6404b3ea1ce9d0999d4d3b65c52f9480",
89
+ "flyctl_schema_bytes": 190611,
90
+ "flyctl_schema_lines": 10995,
91
+ "flyctl_schema_root_query_fields": 39,
92
+ "flyctl_schema_root_mutation_fields": 141,
93
+ "schema_last_change_revision": "acb4fa7a4ea6bad1d9defdf36a8db3be62c6d7b7",
94
+ "schema_provenance": "Manually copied from Fly's internal web repository according to flyctl CONTRIBUTING.md",
95
+ "flyctl_named_documents": 27,
96
+ "flyctl_ad_hoc_documents": 2,
97
+ "fly_go_source_documents": 85,
98
+ "fly_go_unique_root_fields": 52
99
+ },
100
+ "inventories": [
101
+ "flyctl_graphql_operations.json",
102
+ "fly_go_graphql_operations.json",
103
+ "official_docs_graphql_examples.json"
104
+ ],
105
+ "official_sources": [
106
+ "https://fly.io/docs/machines/guides-examples/managing-machines-with-the-api",
107
+ "https://fly.io/docs/mcp/deploy-with/machines-api",
108
+ "https://fly.io/docs/blueprints/using-the-fly-docker-registry"
109
+ ]
110
+ },
111
+ {
112
+ "id": "prometheus_metrics",
113
+ "classification": "public_documented_observability_data_api_not_control_plane",
114
+ "stability": "stable_standard_http_query_api_with_qualified_fly_compatibility",
115
+ "base_url": "https://api.fly.io/prometheus/{org_slug}/",
116
+ "authentication": "Authorization: Bearer or FlyV1 depending on token type",
117
+ "authoritative_contract": "Prometheus HTTP API and VictoriaMetrics compatibility documentation; no Fly-owned OpenAPI",
118
+ "documented_endpoint_families": 7,
119
+ "endpoint_families": [
120
+ "/api/v1/query",
121
+ "/api/v1/query_range",
122
+ "/api/v1/series",
123
+ "/api/v1/labels",
124
+ "/api/v1/label/{label_name}/values",
125
+ "/api/v1/status/tsdb",
126
+ "/federate"
127
+ ],
128
+ "official_source": "https://fly.io/docs/monitoring/metrics"
129
+ },
130
+ {
131
+ "id": "extensions_partner_oauth",
132
+ "classification": "partner_gated_public_integration_api",
133
+ "stability": "no_explicit_stability_label",
134
+ "base_url": "https://api.fly.io",
135
+ "authentication": "OAuth client credentials plus partner-provided shared secrets; token info uses Bearer",
136
+ "authoritative_contract": null,
137
+ "prose_operations": [
138
+ "GET /oauth/authorize",
139
+ "POST /oauth/token",
140
+ "GET /oauth/token/info",
141
+ "POST /api/hooks/extensions/{provider}"
142
+ ],
143
+ "limitations": "Requires enrollment and Fly-provided credentials; page is excluded from sitemap; not a general account control-plane API",
144
+ "official_source": "https://fly.io/docs/reference/extensions_api"
145
+ },
146
+ {
147
+ "id": "flyctl_uiex_rest",
148
+ "classification": "observed_internal_implementation_not_public_contract",
149
+ "stability": "undocumented_internal",
150
+ "base_url": "https://api.fly.io/api/v1",
151
+ "authoritative_contract": null,
152
+ "flyctl_request_call_sites": 52,
153
+ "methods": {"GET": 21, "POST": 20, "PATCH": 3, "DELETE": 8},
154
+ "decision": "Exclude from supported public surface; do not infer stability from flyctl use"
155
+ },
156
+ {
157
+ "id": "tigris_s3_and_fly_registry",
158
+ "classification": "adjacent_data_planes",
159
+ "stability": "Tigris Fly documentation is beta; registry uses external Docker/OCI behavior",
160
+ "authoritative_contract": "External S3 and OCI/Distribution contracts, not Fly control-plane contracts",
161
+ "decision": "Document as out of the control-plane client boundary"
162
+ }
163
+ ]
164
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "retrieved_at": "2026-08-26",
3
+ "rubygems_name": {
4
+ "name": "fly_io",
5
+ "api_url": "https://rubygems.org/api/v1/gems/fly_io.json",
6
+ "api_status": 404,
7
+ "exact_search_matches": [],
8
+ "decision": "Use fly_io; availability is verified but only a publish can reserve it."
9
+ },
10
+ "ruby": {
11
+ "authoritative_url": "https://www.ruby-lang.org/en/downloads/releases/",
12
+ "latest_stable": "4.0.6",
13
+ "released_at": "2026-07-14",
14
+ "source_url": "https://cache.ruby-lang.org/pub/ruby/4.0/ruby-4.0.6.tar.gz",
15
+ "source_sha256": "837d299e8f7ddf2be31a229a7a7e019d354979825117989acb3b32b1a9be262a"
16
+ }
17
+ }
@@ -0,0 +1,474 @@
1
+ ---
2
+ title: Metrics on Fly.io
3
+ layout: docs
4
+ nav: firecracker
5
+ redirect_from:
6
+ - /docs/reference/metrics/
7
+ - /docs/going-to-production/monitoring/publishing-metrics/
8
+ - /docs/metrics-and-logs/metrics
9
+ ---
10
+
11
+ <figure>
12
+ <img src="/static/images/monitor-machines.png" alt="Illustration by Annie Ruygt of some Machines strutting along" class="w-full max-w-lg mx-auto">
13
+ </figure>
14
+
15
+ The Fly.io platform includes a fully-managed metrics solution to help you easily monitor your Fly apps.
16
+ It includes the following components:
17
+
18
+ - [**Prometheus on Fly.io**](#prometheus-on-fly-io): Managed Prometheus-compatible time series storage
19
+ - [**Dashboards**](#dashboards): Managed Grafana with detailed visualizations of all built-in metrics
20
+ - [**Built-in Metrics**](#built-in-metrics): Metrics automatically sent from every Fly app you deploy
21
+ - [**Custom Metrics**](#custom-metrics): Expose additional metrics from Fly apps for further customization
22
+
23
+ ## Prometheus on Fly.io
24
+
25
+ [Prometheus](https://prometheus.io/) is a popular open source monitoring system used to store and query metrics efficiently,
26
+ with a stable [HTTP querying API](https://prometheus.io/docs/prometheus/latest/querying/api/) compatible with a range of systems.
27
+
28
+ **Prometheus on Fly.io** is a fully-managed service based on [VictoriaMetrics](https://victoriametrics.com/).
29
+ It [supports](https://docs.victoriametrics.com/#prometheus-querying-api-usage) most common Prometheus querying API endpoints:
30
+ - [`/api/v1/query`](https://prometheus.io/docs/prometheus/latest/querying/api/#instant-queries)
31
+ - [`/api/v1/query_range`](https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries)
32
+ - [`/api/v1/series`](https://prometheus.io/docs/prometheus/latest/querying/api/#finding-series-by-label-matchers)
33
+ - [`/api/v1/labels`](https://prometheus.io/docs/prometheus/latest/querying/api/#getting-label-names)
34
+ - [`/api/v1/label/<label_name>/values`](https://prometheus.io/docs/prometheus/latest/querying/api/#querying-label-values)
35
+ - [`/api/v1/status/tsdb`](https://prometheus.io/docs/prometheus/latest/querying/api/#tsdb-stats)
36
+ - [`/federate`](https://prometheus.io/docs/prometheus/latest/federation/)
37
+
38
+ Note that [remote read](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_read) (`/api/v1/read`) [remote storage integration](https://prometheus.io/docs/prometheus/latest/storage/#remote-storage-integrations)
39
+ is [not supported](https://docs.victoriametrics.com/FAQ.html#why-doesnt-victoriametrics-support-the-prometheus-remote-read-api).
40
+
41
+ ### MetricsQL
42
+
43
+ Prometheus queries are typically based on the [PromQL](https://prometheus.io/docs/prometheus/latest/querying/basics/) query language.
44
+ Prometheus on Fly.io queries use VictoriaMetrics [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html),
45
+ a backwards-compatible query language that fixes user experience issues and adds
46
+ useful features and functions on top of PromQL.
47
+
48
+ Key features:
49
+
50
+ - [Better `rate()` and `increase()`](https://medium.com/@romanhavronenko/victoriametrics-promql-compliance-d4318203f51e#cade)
51
+ functions that just work. No need for [`irate` workarounds](https://www.percona.com/blog/2020/02/28/better-prometheus-rate-function-with-victoriametrics/)
52
+ or appending Grafana's [magical `$__rate_interval`](https://grafana.com/blog/2020/09/28/new-in-grafana-7.2-__rate_interval-for-prometheus-rate-queries-that-just-work/) selector to every query.
53
+ In fact, you can even omit the square brackets entirely and MetricsQL will do the right thing.
54
+ - Many more [label manipulation functions](https://docs.victoriametrics.com/MetricsQL.html#label-manipulation-functions)
55
+ such as `drop_common_labels`, `label_set`, etc.
56
+ - [`topk_avg`](https://docs.victoriametrics.com/MetricsQL.html#topk_avg), which returns the top `k` time series averaged
57
+ across the entire series range (not just individual points), plus the sum of all remaining series in an "other" label.
58
+ Useful for giving a small, filtered view across a potentially large number of series.
59
+
60
+ ### Querying
61
+
62
+ Queries can be sent to the following endpoint:
63
+ ```
64
+ https://api.fly.io/prometheus/<org-slug>/
65
+ ```
66
+
67
+ You’ll need to authenticate with a [Fly Access Token](https://fly.io/docs/security/tokens/). Depending on the token type, the header uses either the Bearer format (`Authorization: Bearer <token>`) or the FlyV1 format (`Authorization: FlyV1 <token>`). You may only query series scoped to your organizations.
68
+
69
+
70
+ #### Manually
71
+
72
+ **Find your Organization slug**
73
+
74
+ List your organizations, find the org slug and set it as a local variable.
75
+
76
+ ```cmd
77
+ flyctl orgs list
78
+ ORG_SLUG=[org-slug]
79
+ ```
80
+
81
+ **Get an access token**
82
+
83
+ ```cmd
84
+ TOKEN=$(flyctl auth token)
85
+ ```
86
+
87
+ **Test it out!**
88
+
89
+ ```shell
90
+ curl https://api.fly.io/prometheus/$ORG_SLUG/api/v1/query \
91
+ --data-urlencode 'query=sum(increase(fly_edge_http_responses_count)) by (app, status)' \
92
+ -H "Authorization: Bearer $TOKEN"
93
+ ```
94
+
95
+ ## Retention, cost, and limits
96
+
97
+ Prometheus on Fly.io retains metric data for approximately 15 days and is intended for operational monitoring. If you need longer retention, run your own monitoring stack. Fly.io's [Observability for User Apps](/docs/blueprints/observability-for-user-apps/) guide deploys a ready-made stack, or you can federate from the Fly.io endpoint into your own Prometheus installation.
98
+
99
+ There's currently no additional charge for the managed Prometheus and Grafana. Pricing could change in the future, and Fly.io will give advance notice.
100
+
101
+ A couple of practical limits to be aware of:
102
+
103
+ - We cap your app's metrics endpoint response at 16 MB and drop anything larger.
104
+ - We may drop very high-cardinality custom metrics.
105
+
106
+ ## Dashboards
107
+
108
+ For more advanced metrics monitoring, you can use dashboards to organize and visualize complex Prometheus
109
+ queries.
110
+
111
+ The Metrics tab on the [Fly.io Dashboard](https://fly.io/dashboard) provides an overview
112
+ of your Fly apps using the built-in metrics stored in Prometheus.
113
+
114
+ ### Managed Grafana
115
+
116
+ [Grafana](https://grafana.com/) is a popular open source data visualization web application, that allows you to
117
+ compose queries against data sources into dynamic, reusable dashboards.
118
+
119
+ We provide a managed Grafana instance at [fly-metrics.net](https://fly-metrics.net), preconfigured with your
120
+ Prometheus data source and detailed dashboards covering the full set of built-in metrics.
121
+
122
+ You can also use the Explore panel to run ad-hoc queries against the preconfigured Prometheus datasource,
123
+ or create/import additional dashboards for further customization or to visualize custom metrics.
124
+
125
+ Switch between your Fly.io Organizations by clicking the "Switch organization" link beneath
126
+ the user icon in the lower-left of the screen.
127
+
128
+ ### External or self-hosted Grafana
129
+
130
+ You can also configure your Prometheus endpoint with an existing Grafana installation, or [host one on Fly.io](https://github.com/fly-apps/grafana). Either way, you can set it up like this:
131
+
132
+ 1. [Add](https://grafana.com/docs/grafana/latest/datasources/add-a-data-source/) a [Prometheus data source](https://grafana.com/docs/grafana/latest/datasources/prometheus/) (Settings -> Data Sources -> Add data source -> Prometheus)
133
+ 2. Fill the form with the following:
134
+ - HTTP -> URL: `https://api.fly.io/prometheus/<org-slug>/`
135
+ - Custom HTTP Headers -> + Add Header:
136
+ - Header: `Authorization`
137
+ - Value: `FlyV1 <token>` (for tokens created with `fly tokens create`)
138
+ - Value: `Bearer <token>` (only for tokens from `flyctl auth token`)
139
+
140
+ You're all set.
141
+
142
+ We publish our [Fly.io Dashboards](https://grafana.com/grafana/dashboards/14741) to Grafana.com for use with external Grafana instances.
143
+ To install, just [import the dashboard](https://grafana.com/docs/grafana/latest/dashboards/export-import/#import-dashboard) using the listed IDs.
144
+ If you'd like to contribute changes to the dashboards, we have created a [repository](https://github.com/superfly/dashboards) for them.
145
+
146
+ ## Alerting
147
+
148
+ Fly.io doesn't include built-in alerting on metrics, so you'll need to set up alerting yourself against the Prometheus endpoint. Two common approaches:
149
+
150
+ - **Grafana alerting**: connect the Fly.io Prometheus data source to a Grafana instance (see the [External or self-hosted Grafana](#external-or-self-hosted-grafana) section), then create [Grafana alert rules](https://grafana.com/docs/grafana/latest/alerting/) on queries against the data source and send the alerts to a contact point such as email, Slack, or PagerDuty.
151
+ - **Prometheus and Alertmanager**: run your own [Prometheus](https://prometheus.io/) that federates from the Fly.io endpoint and use [Alertmanager](https://prometheus.io/docs/alerting/latest/alertmanager/) to send notifications.
152
+
153
+ If you don't already run Grafana or Prometheus, Fly.io's [Observability for User Apps](/docs/blueprints/observability-for-user-apps/) guide deploys a ready-made stack (VictoriaMetrics and Grafana) you can build alerts on.
154
+
155
+ ## Built-in metrics
156
+
157
+ Fly apps automatically publish a number of built-in metrics.
158
+
159
+ [Metric types](https://prometheus.io/docs/concepts/metric_types/) are all [Gauges](https://prometheus.io/docs/concepts/metric_types/#gauge)
160
+ unless otherwise marked.
161
+
162
+ Metrics with names ending in `_count` are all [Counters](https://prometheus.io/docs/concepts/metric_types/#counter).
163
+
164
+ [Histogram](https://prometheus.io/docs/concepts/metric_types/#histogram) metrics with a base name of `<name>` expose multiple series:
165
+ - `<name>_bucket{le}`
166
+ - `<name>_sum`
167
+ - `<name>_count`
168
+
169
+ ### Standard Labels
170
+
171
+ All published series include the following labels:
172
+
173
+ - `app`: App name
174
+ - `region`: [Fly.io Region](https://fly.io/docs/reference/regions/#fly-io-regions)
175
+ - `host`: 4-character host ID (lowercase hexadecimal)
176
+ - `instance`: App instance ID (for all series except `fly_edge_` and `fly_volume_`)
177
+
178
+ If your app exposes custom metrics with the same labels, they will be overwritten.
179
+
180
+ ### Proxy series
181
+
182
+ Any app using a TCP-based handler (HTTP, TLS or straight TCP) publishes `edge` and `app` proxy metrics:
183
+
184
+ Labels:
185
+ - `proxy_id`: "blue" or "green" (flips when the proxy is restarted/updated)
186
+
187
+ #### Edge - `fly_edge_`
188
+
189
+ ```
190
+ fly_edge_http_responses_count{status}
191
+ fly_edge_http_response_time_seconds{status} (Histogram)
192
+ fly_edge_tcp_connects_count
193
+ fly_edge_tcp_disconnects_count
194
+ fly_edge_data_out (Counter, bytes)
195
+ fly_edge_data_in (Counter, bytes)
196
+ fly_edge_tls_handshake_errors{servername} (Counter)
197
+ fly_edge_tls_handshake_time_seconds{version} (Histogram)
198
+ ```
199
+
200
+ #### App - `fly_app_`
201
+ ```
202
+ fly_app_concurrency
203
+ fly_app_http_responses_count{status}
204
+ fly_app_http_response_time_seconds{status} (Histogram)
205
+ fly_app_connect_time_seconds (Histogram)
206
+ fly_app_tcp_connects_count
207
+ fly_app_tcp_disconnects_count
208
+ ```
209
+
210
+ ### Instance series - `fly_instance_`
211
+
212
+ Derived from the [`/proc` file system](https://www.kernel.org/doc/html/latest/filesystems/proc.html) of your app VMs.
213
+
214
+ `fly_instance_up = 1` shows the VM is reporting correctly.
215
+
216
+ ### Instance exit - `fly_instance_exit_`
217
+
218
+ Information about instance exits. These metrics help you understand why your instances are terminating and can be used for alerting and debugging.
219
+
220
+ - `fly_instance_exit_code`: The exit code of the main process when the instance terminates. A value of 0 typically indicates normal termination, while non-zero values indicate errors or abnormal termination.
221
+ - `fly_instance_exit_oom`: A boolean flag (0 or 1) indicating whether the instance was killed due to out-of-memory (OOM). A value of 1 means the instance was terminated because it exceeded its memory limits.
222
+ - `fly_instance_exit_vm_code`: The VM-level exit code, which may differ from the application exit code. This can help distinguish between application-level failures and VM-level issues.
223
+
224
+ #### Instance memory - `fly_instance_memory_`
225
+
226
+ Derived from [`/proc/meminfo`](https://www.kernel.org/doc/html/latest/filesystems/proc.html#meminfo). All units are in *bytes*.
227
+
228
+ ```
229
+ fly_instance_memory_mem_total
230
+ fly_instance_memory_mem_free
231
+ fly_instance_memory_mem_available
232
+ fly_instance_memory_buffers
233
+ fly_instance_memory_cached
234
+ fly_instance_memory_swap_cached
235
+ fly_instance_memory_active
236
+ fly_instance_memory_inactive
237
+ fly_instance_memory_swap_total
238
+ fly_instance_memory_swap_free
239
+ fly_instance_memory_dirty
240
+ fly_instance_memory_writeback
241
+ fly_instance_memory_slab
242
+ fly_instance_memory_shmem
243
+ fly_instance_memory_vmalloc_total
244
+ fly_instance_memory_vmalloc_used
245
+ fly_instance_memory_vmalloc_chunk
246
+ ```
247
+ #### Instance Load and CPU
248
+
249
+ - `load_average` is derived from [`/proc/loadavg`](https://www.kernel.org/doc/html/latest/filesystems/proc.html#id11) ([`getloadavg`](https://man7.org/linux/man-pages/man3/getloadavg.3.html)). It's a ["system load average"](https://www.brendangregg.com/blog/2017-08-08/linux-load-averages.html) measuring the number of processes in the system run queue, with samples representing averages over 1, 5, and 15 `minutes`.
250
+
251
+ - `cpu` is derived from [`/proc/stat`](https://www.kernel.org/doc/html/latest/filesystems/proc.html#miscellaneous-kernel-statistics-in-proc-stat),
252
+ and counts the amount of time each CPU (`cpu_id`) has spent performing different kinds of work (`mode`, which may be one of `user`, `nice`, `system`, `idle`, `iowait`, `irq`, `softirq`, `steal`, `guest`, `guest_nice`).
253
+ The time unit is 'clock ticks' of centiseconds (0.01 seconds).
254
+
255
+ The following CPU metrics are related to [CPU Performance](/docs/machines/cpu-performance):
256
+ - `cpu_baseline` is the baseline quota in number of CPUs, calculated from the CPU type and number of vCPUs.
257
+ - `cpu_balance` is the accrued CPU burst balance in clock ticks (centiseconds).
258
+ - `cpu_throttle` is derived from the `throttled_time` field of the cgroup [`cpu.stat`](https://docs.kernel.org/scheduler/sched-bwc.html#statistics), and counts the amount of time the CPU was throttled after exhausting its quota, in 'clock ticks' (centiseconds).
259
+
260
+ ```
261
+ fly_instance_load_average{minutes}
262
+ fly_instance_cpu{cpu_id, mode} (Counter, centiseconds)
263
+ fly_instance_cpu_baseline (CPUs)
264
+ fly_instance_cpu_balance (centiseconds)
265
+ fly_instance_cpu_throttle (Counter, centiseconds)
266
+ ```
267
+ #### Instance Disks - `fly_instance_disk_`
268
+
269
+ Counters derived from fields 1-11 of [`/proc/diskstats`](https://www.kernel.org/doc/html/latest/admin-guide/iostats.html). The unit for `time_` series is **milliseconds**, and the unit for `sectors_` is 512-byte sectors.
270
+
271
+ Labels:
272
+ - `device`: Published for the ephemeral VM root disk (`vdb`) and any mounted Volume (`vdc`).
273
+
274
+ ```
275
+ fly_instance_disk_reads_completed
276
+ fly_instance_disk_reads_merged
277
+ fly_instance_disk_sectors_read
278
+ fly_instance_disk_time_reading
279
+ fly_instance_disk_writes_completed
280
+ fly_instance_disk_writes_merged
281
+ fly_instance_disk_sectors_written
282
+ fly_instance_disk_time_writing
283
+ fly_instance_disk_io_in_progress
284
+ fly_instance_disk_time_io
285
+ fly_instance_disk_time_io_weighted
286
+ ```
287
+
288
+ #### Instance Networking - `fly_instance_net_`
289
+
290
+ Counters derived from [`/proc/net/dev`](https://www.kernel.org/doc/html/latest/networking/statistics.html#procfs).
291
+
292
+ Labels:
293
+ - `device`: interface name, either `eth0` or `dummy0` (ignore).
294
+
295
+ ```
296
+ fly_instance_net_recv_bytes
297
+ fly_instance_net_recv_packets
298
+ fly_instance_net_recv_errs
299
+ fly_instance_net_recv_drop
300
+ fly_instance_net_recv_fifo
301
+ fly_instance_net_recv_frame
302
+ fly_instance_net_recv_compressed
303
+ fly_instance_net_recv_multicast
304
+ fly_instance_net_sent_bytes
305
+ fly_instance_net_sent_packets
306
+ fly_instance_net_sent_errs
307
+ fly_instance_net_sent_drop
308
+ fly_instance_net_sent_fifo
309
+ fly_instance_net_sent_colls
310
+ fly_instance_net_sent_carrier
311
+ fly_instance_net_sent_compressed
312
+ ```
313
+
314
+ #### Instance File Descriptors - `fly_instance_filefd_`
315
+
316
+ Information about allocated, and maximum allowed allocated file descriptors derived from [`/proc/sys/fs/file-nr`](https://www.kernel.org/doc/html/latest/admin-guide/sysctl/fs.html#file-max-file-nr).
317
+
318
+ ```
319
+ fly_instance_filefd_allocated
320
+ fly_instance_filefd_maximum
321
+ ```
322
+
323
+ #### Instance Filesystem - `fly_instance_filesystem_`
324
+
325
+ Filesystem metrics derived from [VFS File System Information](https://man7.org/linux/man-pages/man0/sys_statvfs.h.0p.html).
326
+
327
+ Labels:
328
+ - `mount`: mount point name(s), `/` and if using [Volumes](https://fly.io/docs/volumes/), the destination name in fly.toml.
329
+
330
+ ```
331
+ fly_instance_filesystem_blocks
332
+ fly_instance_filesystem_block_size
333
+ fly_instance_filesystem_blocks_free
334
+ fly_instance_filesystem_blocks_avail
335
+ ```
336
+
337
+ ### Volumes - `fly_volume_`
338
+
339
+ Labels:
340
+ - `id`: Volume ID
341
+
342
+ If you're using [Volumes](https://fly.io/docs/volumes/) for any of your organization's apps, you'll be able to query these series,
343
+ derived from the `LSize` and `Data%` of the volume's [thin LV](https://man7.org/linux/man-pages/man7/lvmthin.7.html).
344
+
345
+ ```
346
+ fly_volume_size_bytes
347
+ fly_volume_used_pct (0-100)
348
+ ```
349
+
350
+ ### Postgres - `pg_`
351
+
352
+ If you have a [Postgres](https://fly.io/docs/reference/postgres/) database hosted on Fly.io, you'll automatically get the following series,
353
+ published via [`postgres_exporter`](https://github.com/prometheus-community/postgres_exporter):
354
+
355
+ ```
356
+ pg_stat_activity_count
357
+ pg_stat_activity_max_tx_duration
358
+ pg_stat_archiver_archived_count
359
+ pg_stat_archiver_failed_count
360
+ pg_stat_bgwriter_buffers_alloc
361
+ pg_stat_bgwriter_buffers_backend_fsync
362
+ pg_stat_bgwriter_buffers_backend
363
+ pg_stat_bgwriter_buffers_checkpoint
364
+ pg_stat_bgwriter_buffers_clean
365
+ pg_stat_bgwriter_checkpoint_sync_time
366
+ pg_stat_bgwriter_checkpoint_write_time
367
+ pg_stat_bgwriter_checkpoints_req
368
+ pg_stat_bgwriter_checkpoints_timed
369
+ pg_stat_bgwriter_maxwritten_clean
370
+ pg_stat_bgwriter_stats_reset
371
+ pg_stat_database_blk_read_time
372
+ pg_stat_database_blk_write_time
373
+ pg_stat_database_blks_hit
374
+ pg_stat_database_blks_read
375
+ pg_stat_database_conflicts_confl_bufferpin
376
+ pg_stat_database_conflicts_confl_deadlock
377
+ pg_stat_database_conflicts_confl_lock
378
+ pg_stat_database_conflicts_confl_snapshot
379
+ pg_stat_database_conflicts_confl_tablespace
380
+ pg_stat_database_conflicts
381
+ pg_stat_database_deadlocks
382
+ pg_stat_database_numbackends
383
+ pg_stat_database_stats_reset
384
+ pg_stat_database_tup_deleted
385
+ pg_stat_database_tup_fetched
386
+ pg_stat_database_tup_inserted
387
+ pg_stat_database_tup_returned
388
+ pg_stat_database_tup_updated
389
+ pg_stat_database_xact_commit
390
+ pg_stat_database_xact_rollback
391
+ pg_stat_replication_pg_current_wal_lsn_bytes
392
+ pg_stat_replication_pg_wal_lsn_diff
393
+ pg_stat_replication_reply_time
394
+ pg_replication_lag
395
+ pg_database_size_bytes
396
+ ```
397
+
398
+ ## Custom Metrics
399
+
400
+ For further customization beyond built-in metrics,
401
+ Fly apps can expose a metrics endpoint we'll automatically scrape every 15 seconds and
402
+ send the results to Prometheus.
403
+
404
+ ### Configuration
405
+
406
+ Add a `[metrics]` section to your application's `fly.toml`:
407
+
408
+ ```toml
409
+ [metrics]
410
+ port = 9091
411
+ path = "/metrics" # default for most prometheus exporters
412
+ ```
413
+
414
+ If your app uses [multiple processes](/docs/apps/processes/), you can add multiple `[[metrics]]` sections, each with its own set of `processes`:
415
+
416
+ ```toml
417
+ [[metrics]]
418
+ port = 9394
419
+ path = "/metrics"
420
+ processes = ["web"]
421
+
422
+ [[metrics]]
423
+ port = 9113
424
+ path = "/metrics"
425
+ processes = ["proxy"]
426
+ ```
427
+
428
+ ### Instrumentation
429
+
430
+ Instrument your app and expose your metrics on `0.0.0.0`.
431
+
432
+ There are many supported [client libraries](https://prometheus.io/docs/instrumenting/clientlibs/) as well as off-the-shelf [exporters](https://prometheus.io/docs/instrumenting/exporters/) able to return Prometheus-formatted metrics.
433
+
434
+ ## Authentication
435
+
436
+ Authenticating to the Prometheus API can be achieved a few different ways, depending on the level of access you want your token to have.
437
+
438
+ ### Fly Access Token
439
+
440
+ As in the earlier example, a full access token can be generated with `flyctl auth token` and then passed as a bearer token in the `Authorization` header. The header looks like:
441
+
442
+ ```
443
+ Authorization: Bearer THE_TOKEN
444
+ ```
445
+
446
+ ### Fly org-restricted or read-only token
447
+
448
+ This kind of token or "[macaroon](https://fly.io/blog/macaroons-escalated-quickly/)" can be scoped to a single organization or configured to only allow read operations, which can be safer than using a full-blown read-write token that grants access to all organizations under your account.
449
+
450
+ ### Generating tokens
451
+ Create an org-restricted token:
452
+
453
+ ```
454
+ fly tokens create org -o THE_ORGANIZATION
455
+ ```
456
+
457
+ Create a read-only org-restricted token:
458
+
459
+ ```
460
+ fly tokens create readonly
461
+ ```
462
+
463
+ These tokens look like this once generated: `FlyV1 fm2_lJPECAAAAAAAAC7txBAzYI6PRWhHLT...(a lot of base64-encoded text)`.
464
+
465
+ #### Using tokens
466
+ Use the correct scheme based on token type:
467
+
468
+ - `Bearer <token>` → for `flyctl auth token`.
469
+ - `FlyV1 <token>` → for all tokens created with `fly tokens create`.
470
+
471
+ Example with a token created via `fly tokens create`:
472
+ ```
473
+ Authorization: FlyV1 fm2_lJPECAAAAAAAAC7txBAzYI6PRWhHLT...(a lot of base64-encoded text)
474
+ ```