Application Observability host-hours pricing
Grafana Cloud Application Observability bills based on host hours — the total number of hours per month that each host sends application telemetry to Grafana Cloud. This pricing model applies to every customer that uses Application Observability.
- Self-Serve users on Pro and Advanced plans: The pricing model was applied on September 1, 2024.
- Contracted organizations: The pricing model is applied upon contract renewal.
Starting February 13, 2026, Application Observability introduces a new pricing model:
- All new customers: $0.025 per host hour plus separate charges for telemetry (metrics, traces, logs, profiles) at $0.50 per 1,000 active series (metrics) and $0.50 per GB for traces, logs, and profiles. This model does not include telemetry credits.
- Existing customers (before February 13, 2026): $0.04 per host hour with included telemetry credits (1.5 active series and 0.02 GB of traces per host hour). Standard pricing applies for usage exceeding included credits.
For information about pricing and billing for Application Observability, refer to these resources:
- Grafana Cloud Pricing for Application Observability
- Understand your Application Observability Invoice
Note
For serverless environments including Container as a Service (CaaS) and Function as a Service (FaaS) platforms (such as AWS Lambda, Google Cloud Functions, Azure Functions, and others), Application Observability uses telemetry-based billing instead of host-hours. You pay only for the telemetry (metrics, traces, logs, profiles) ingested into Grafana Cloud. Contact Grafana Support to ensure your environment is correctly configured for serverless billing.
Definition of host
Hosts can be any of the following:
- Physical Servers: Dedicated machines that run an operating system and applications.
- Virtual Machines (VMs): Instances of operating systems running on virtualized environments, such as those managed by VMware, Hyper-V, or cloud providers like AWS EC2, Azure Virtual Machines, and so on.
What is not a host
A container is an isolated application environment running on a host system. Containers, like those managed by Docker, are not considered hosts because they do not represent a full operating system instance.
How Application Observability identifies hosts
Application Observability identifies hosts from standard OpenTelemetry resource attributes attached to your telemetry. To make billing work, two things matter: which metric-generation path your telemetry follows on its way to Grafana Cloud, and which host resource attribute is present on the resulting metrics. The priority list below shows the supported attributes; the rest of this section walks through both.
For every service, Application Observability evaluates the following resource attributes in priority order and uses the first match as the host’s billing identifier — you only need to satisfy one tier, not all three:
Priority 3 (grafana.host.id) is not emitted automatically by any tool — it’s an explicit opt-in attribute that you set deliberately when neither priority 1 nor priority 2 is available in your environment.
If none of these attributes are present on a service’s telemetry, the service is not counted for host-hours billing and Application Observability surfaces a configuration warning. This is the safe failure mode — services without a verifiable host identifier are excluded rather than billed under an unreliable key.
Which metric-generation path applies to you?
Application Observability supports three paths for the metrics that feed host identification. For all three, the host resource attribute must be present on the resulting metrics — see Make sure your hosts are identified for per-environment setup. Each path differs in how the metrics are produced and whether any extra pipeline tagging is needed:
- Tempo metrics-generator (default): Traces sent to Grafana Cloud are processed by Tempo’s metrics-generator, which derives RED metrics from them. No extra collector configuration for host identification.
- Beyla/OBI eBPF auto-instrumentation: Beyla (or its upstream OpenTelemetry counterpart, OBI) emits RED metrics directly and detects
k8s.node.name,host.name, andcloud.providernatively for most deployment models. No extra collector configuration for host identification. - Collector-side
spanmetricsconnector: You generate RED metrics in your own Grafana Alloy or OpenTelemetry Collector via thespanmetricsconnector, and spans don’t reach Tempo’s metrics-generator. Tag the connector’s output metrics withsource=spanmetrics(see Setsource=spanmetrics) — the connector doesn’t add the attribute on its own.
If you’re not sure which path applies, the default is the Tempo metrics-generator path for traces from the OpenTelemetry SDKs / Alloy / OpenTelemetry Collector. You’re on the collector-side path only if you’ve explicitly configured a spanmetrics connector in your collector. To check, search your collector configuration file for connectors: sections containing spanmetrics (OpenTelemetry Collector) or otelcol.connector.spanmetrics (Grafana Alloy).
Make sure your hosts are identified
Confirm one of the priority tiers is satisfied for each environment that sends telemetry to Application Observability. Start with priority 1 if you run on Kubernetes, priority 2 if you run on cloud VMs, and only fall back to priority 3 when neither applies.
Priority 1: k8s.node.name (Kubernetes)
Run the k8sattributes processor on your collector or gateway so it stamps k8s.node.name on incoming telemetry. The Grafana Cloud Kubernetes Monitoring Helm chart configures this for you. Beyla emits k8s.node.name natively on Kubernetes — no additional configuration is needed.
If you instrument applications with the OpenTelemetry SDK directly (no collector in the path), inject k8s.node.name via the Downward API:
spec:
containers:
- name: app
env:
- name: K8S_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: OTEL_RESOURCE_ATTRIBUTES
value: "k8s.node.name=$(K8S_NODE_NAME)"Without this, host.name resolves to the pod name and every pod is counted as a separate host.
Priority 2: host.name and cloud.provider (cloud VMs)
On cloud VMs (AWS, GCP, Azure), enable the cloud-specific resource detector on your collector agent. It queries the cloud Instance Metadata Service (IMDS) and sets both host.name and cloud.provider:
// Substitute ec2 with gcp or azure as appropriate
otelcol.processor.resourcedetection "default" {
detectors = ["env", "ec2"]
ec2 {
resource_attributes {
host.name { enabled = true }
cloud.provider { enabled = true }
cloud.platform { enabled = true }
}
}
// output: wire to your next component
output {}
}# AWS EC2 — substitute gcp or azure as appropriate
processors:
resourcedetection:
detectors: [env, ec2]
override: true
ec2:
resource_attributes:
host.name: {enabled: true}
cloud.provider: {enabled: true}
cloud.platform: {enabled: true}
# Add resourcedetection to service.pipelines processorsBeyla detects these attributes natively on cloud VMs — no additional configuration is needed.
Note
cloud.provideris matched against the exact valuesaws,gcp, andazure(canonical lowercase, as emitted by the OpenTelemetry resource detectors). Any other value — includingAWS,GCP,Azure, or a custom string — does not satisfy this priority, and detection falls through tografana.host.id.
Priority 3: grafana.host.id (last-resort fallback)
grafana.host.id is the last-resort identifier. Only set it when neither priority 1 nor priority 2 is available — typically on bare metal, in Docker on hardware you manage, or in on-premises Kubernetes deployments where k8sattributes and a cloud resource detector are both absent. Unlike priorities 1 and 2, no tool emits grafana.host.id automatically; you must set it deliberately on your collector.
Bare metal
Set grafana.host.id on your collector agent by copying host.name into it. This gives the host a stable, explicit identifier.
Note
The
host.namevalue should be stable (persist across reboots), unique (different for each physical/virtual host), and meaningful (helps identify the host in your infrastructure). The system hostname typically satisfies these requirements.
otelcol.processor.resourcedetection "default" {
detectors = ["env", "system"]
system {
hostname_sources = ["dns", "os"]
resource_attributes {
host.name { enabled = true }
}
}
output {
traces = [otelcol.processor.transform.add_host_id.input]
metrics = [otelcol.processor.transform.add_host_id.input]
logs = [otelcol.processor.transform.add_host_id.input]
}
}
otelcol.processor.transform "add_host_id" {
error_mode = "ignore"
trace_statements {
context = "resource"
statements = [`set(attributes["grafana.host.id"], attributes["host.name"])`]
}
metric_statements {
context = "resource"
statements = [`set(attributes["grafana.host.id"], attributes["host.name"])`]
}
log_statements {
context = "resource"
statements = [`set(attributes["grafana.host.id"], attributes["host.name"])`]
}
// output: wire to your next component
output {}
}processors:
resourcedetection:
detectors: [env, system]
system:
hostname_sources: [dns, os]
resource_attributes:
host.name: {enabled: true}
resource:
attributes:
- key: grafana.host.id
from_attribute: host.name
action: insert
# Add resourcedetection and resource to service.pipelines processorsDocker
Set OTEL_RESOURCE_ATTRIBUTES to inject the host identifier. Replace my-server-hostname with your host’s actual identifier:
# Static value
docker run -e OTEL_RESOURCE_ATTRIBUTES="grafana.host.id=prod-web-01" ...
# Or use dynamic hostname
docker run -e OTEL_RESOURCE_ATTRIBUTES="grafana.host.id=$(hostname)" ...services:
collector:
environment:
# Replace with your host's actual identifier
OTEL_RESOURCE_ATTRIBUTES: "grafana.host.id=prod-web-01"Then configure your collector to read it:
otelcol.processor.resourcedetection "default" {
detectors = ["env"]
// output: wire to your next component
output {}
}processors:
resourcedetection:
detectors: [env]
# Add resourcedetection to service.pipelines processorsPassthrough gateway
If you run an OpenTelemetry Collector as a passthrough gateway in front of a collector agent that has already set host attributes, set override: false on the gateway’s resourcedetection processor. The default of true causes the gateway to silently overwrite the agent’s host attributes with its own identity, which leads to over-counting:
otelcol.processor.resourcedetection "default" {
detectors = ["env"]
override = false
// output: wire to your next component
output {}
}processors:
resourcedetection:
detectors: [env]
override: false
# Add resourcedetection to service.pipelines processorsSet source=spanmetrics
On the collector-side spanmetrics path, tag the metrics the connector produces with a source=spanmetrics resource attribute so Application Observability recognizes their target_info series for host identification. Add a transform processor after the spanmetrics connector and before the exporter that sets the attribute. Using context: scope runs the statement once per scope rather than once per data point; the where name == "spanmetricsconnector" condition scopes the change to metrics the connector produced, leaving any other metrics that pass through the processor untouched:
otelcol.processor.transform "add_source" {
error_mode = "ignore"
metric_statements {
context = "scope"
statements = [
`set(resource.attributes["source"], "spanmetrics") where name == "spanmetricsconnector"`,
]
}
output {
metrics = [otelcol.processor.batch.default.input]
}
}Wire the connector’s metrics output into the processor so every generated metric is tagged before export:
otelcol.connector.spanmetrics "default" {
// ... your span metrics configuration ...
output {
metrics = [otelcol.processor.transform.add_source.input]
}
}processors:
transform/add_source:
metric_statements:
- context: scope
statements:
- set(resource.attributes["source"], "spanmetrics") where name == "spanmetricsconnector"
service:
pipelines:
# the metrics pipeline fed by the spanmetrics connector
metrics/spanmetrics:
receivers: [spanmetrics]
processors: [transform/add_source, batch]
exporters: [prometheusremotewrite]Configure the host_info / grafanacloud connector
Warning
The
host_info/grafanacloudconnector and thetraces_host_infometric it emits are deprecated but supported for the time being. New setups should send the host resource attributes listed in How Application Observability identifies hosts instead.
The connector inspects each span’s resource attributes in priority order and emits a traces_host_info metric tagged with the resolved host identifier. Configure host_identifiers to mirror the host-identification priority above — k8s.node.name, host.name, then grafana.host.id.
otelcol.connector.host_info "default" {
host_identifiers = ["k8s.node.name", "host.name", "grafana.host.id"]
output {
metrics = [otelcol.processor.batch.default.input]
}
}Wire the connector into the traces output of your OTLP receiver so every received span flows to it:
otelcol.receiver.otlp "default" {
grpc { }
http { }
output {
traces = [
otelcol.processor.batch.default.input,
otelcol.connector.host_info.default.input,
]
}
}For the full Alloy configuration, refer to the Alloy setup documentation.
connectors:
grafanacloud:
host_identifiers: [k8s.node.name, host.name, grafana.host.id]
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp/tempo, grafanacloud]
metrics/host_info:
receivers: [grafanacloud]
processors: [batch]
exporters: [prometheusremotewrite]For the full OpenTelemetry Collector configuration, refer to the OpenTelemetry Collector setup documentation.
The traces_host_info metric
If your Grafana Cloud stack receives the traces_host_info metric — produced when a host_info (Grafana Alloy) or grafanacloud (OpenTelemetry Collector) connector is wired into a collector pipeline that sends to the stack — Application Observability uses it as the host identifier for the whole stack rather than the resource attributes listed in How Application Observability identifies hosts, even when those attributes are present. The switch is stack-wide: to have hosts identified from resource attributes instead, you must remove the connector from every collector pipeline writing to the stack, so that traces_host_info is no longer ingested. Migrating one collector or one service at a time is not possible.
Host identification notification
If Application Observability can’t identify a host for one or more of your services, the system displays a notification. To resolve it, follow the host identification checklist for your environment.
If you don’t plan to use Application Observability any longer, read how to disable it to avoid charges.
Disable Application Observability in Grafana Cloud
If you don’t want to use Application Observability in Grafana Cloud or incur billing, you can disable it.
Caution
If you follow these steps, you lose the visibility provided by Grafana Cloud Application Observability.
- Select Configuration under Application in the left navigation of your Grafana Cloud instance.
- Click the System tab.
- Under Deactivate Application Observability, click Deactivate.


